libhaystack/c_api/value.rs
1// Copyright (C) 2020 - 2022, J2 Innovations
2
3//!
4//! C API for working with the [Value](crate::val::Value) type.
5//!
6
7use super::err::new_error;
8use crate::haystack::val::{Date, Dict, Grid, List, Time, Value};
9use crate::safe_bool_call;
10use crate::units::get_unit;
11use chrono::{NaiveDateTime, TimeZone, Utc};
12
13use std::ffi::CStr;
14use std::os::raw::c_char;
15
16/// Construct an empty [Value](crate::val::Value)
17/// # Example
18/// ```rust
19/// # use crate::libhaystack::val::Value;
20/// # use crate::libhaystack::c_api::value::*;
21/// let val = haystack_value_init();
22/// # unsafe {
23/// # let val = Box::<Value>::leak(val);
24/// assert!(haystack_value_is_null(val))
25/// # }
26/// ```
27#[unsafe(no_mangle)]
28pub extern "C" fn haystack_value_init() -> Box<Value> {
29 Box::<Value>::default()
30}
31
32/// Destructs and free a [Value](crate::val::Value)
33/// # Arguments
34/// val a [Value](crate::val::Value).
35///
36/// # Example
37/// ```rust
38/// # use crate::libhaystack::val::Value;
39/// # use crate::libhaystack::c_api::value::*;
40/// let val = haystack_value_init();
41/// # unsafe {
42/// # let val = Box::<Value>::leak(val);
43/// haystack_value_destroy(val);
44/// # }
45/// ```
46/// # Safety
47/// Panics on invalid input data
48#[unsafe(no_mangle)]
49pub unsafe extern "C" fn haystack_value_destroy(val: *mut Value) {
50 if !val.is_null() {
51 drop(unsafe { Box::from_raw(val) });
52 }
53}
54
55/// True if a null (empty) [Value](crate::val::Value)
56/// # Arguments
57/// val a [Value](crate::val::Value).
58/// # Example
59/// ```rust
60/// # use crate::libhaystack::val::Value;
61/// # use crate::libhaystack::c_api::value::*;
62/// let val = haystack_value_init();
63/// # unsafe {
64/// # let val = Box::<Value>::leak(val);
65/// assert!(haystack_value_is_null(val))
66/// # }
67/// ```
68/// # Safety
69/// Panics on invalid input data
70#[unsafe(no_mangle)]
71pub unsafe extern "C" fn haystack_value_is_null(val: *const Value) -> bool {
72 safe_bool_call!(val, is_null)
73}
74
75/// Construct a [Marker](crate::val::Marker) [Value](crate::val::Value)
76#[unsafe(no_mangle)]
77pub extern "C" fn haystack_value_make_marker() -> Box<Value> {
78 Box::new(Value::make_marker())
79}
80
81/// True if a [Marker](crate::val::Marker) [Value](crate::val::Value)
82/// # Arguments
83/// val a [Value](crate::val::Value).
84/// # Returns
85/// True, or False in which case if argument type mismatch an error is created that can be read using
86/// [last_error_message](super::err::last_error_message)
87/// # Example
88/// ```rust
89/// # use crate::libhaystack::val::Value;
90/// # use crate::libhaystack::c_api::value::*;
91/// let val = haystack_value_make_marker();
92/// # unsafe {
93/// # let val = Box::<Value>::leak(val);
94/// assert!(haystack_value_is_marker(val))
95/// # }
96/// ```
97/// # Safety
98/// Panics on invalid input data
99#[unsafe(no_mangle)]
100pub unsafe extern "C" fn haystack_value_is_marker(val: *const Value) -> bool {
101 safe_bool_call!(val, is_marker)
102}
103
104/// Construct a [NA](crate::val::Na) [Value](crate::val::Value)
105#[unsafe(no_mangle)]
106pub extern "C" fn haystack_value_make_na() -> Box<Value> {
107 Box::new(Value::make_na())
108}
109
110/// True if a [NA](crate::val::Na) [Value](crate::val::Value)
111/// # Arguments
112/// val a [Value](crate::val::Value).
113/// # Returns
114/// True, or False in which case if argument type mismatch an error is created that can be read using
115/// [last_error_message](super::err::last_error_message)
116/// # Example
117/// ```rust
118/// # use crate::libhaystack::val::Value;
119/// # use crate::libhaystack::c_api::value::*;
120/// let val = haystack_value_make_na();
121/// # unsafe {
122/// # let val = Box::<Value>::leak(val);
123/// assert!(!haystack_value_is_null(val));
124/// assert!(haystack_value_is_na(val));
125/// # }
126/// ```
127/// # Safety
128/// Panics on invalid input data
129#[unsafe(no_mangle)]
130pub unsafe extern "C" fn haystack_value_is_na(val: *const Value) -> bool {
131 safe_bool_call!(val, is_na)
132}
133
134/// Construct a [Remove](crate::val::Remove) [Value](crate::val::Value)
135#[unsafe(no_mangle)]
136pub extern "C" fn haystack_value_make_remove() -> Box<Value> {
137 Box::new(Value::make_remove())
138}
139
140/// True if a [Remove](crate::val::Remove) [Value](crate::val::Value)
141/// # Arguments
142/// val a [Value](crate::val::Value).
143/// # Returns
144/// True, or False in which case if argument type mismatch an error is created that can be read using
145/// [last_error_message](super::err::last_error_message)
146/// # Example
147/// ```rust
148/// # use crate::libhaystack::val::Value;
149/// # use crate::libhaystack::c_api::value::*;
150/// let val = haystack_value_make_remove();
151/// # unsafe {
152/// # let val = Box::<Value>::leak(val);
153/// assert!(!haystack_value_is_null(val));
154/// assert!(haystack_value_is_remove(val));
155/// # }
156/// ```
157/// # Safety
158/// Panics on invalid input data
159#[unsafe(no_mangle)]
160pub unsafe extern "C" fn haystack_value_is_remove(val: *const Value) -> bool {
161 safe_bool_call!(val, is_remove)
162}
163
164/// Construct a [Bool](crate::val::Bool) [Value](crate::val::Value)
165#[unsafe(no_mangle)]
166pub extern "C" fn haystack_value_make_bool(val: bool) -> Box<Value> {
167 Box::new(Value::make_bool(val))
168}
169
170/// True if a [Bool](crate::val::Bool) [Value](crate::val::Value)
171/// # Arguments
172/// val a [Value](crate::val::Value).
173/// # Returns
174/// True, or False in which case if argument type mismatch an error is created that can be read using
175/// [last_error_message](super::err::last_error_message)
176/// # Example
177/// ```rust
178/// # use crate::libhaystack::val::Value;
179/// # use crate::libhaystack::c_api::value::*;
180/// let val = haystack_value_make_bool(true);
181/// # unsafe {
182/// # let val = Box::<Value>::leak(val);
183/// assert!(!haystack_value_is_na(val));
184/// assert!(haystack_value_is_bool(val));
185/// # }
186/// ```
187/// # Safety
188/// Panics on invalid input data
189#[unsafe(no_mangle)]
190pub unsafe extern "C" fn haystack_value_is_bool(val: *const Value) -> bool {
191 safe_bool_call!(val, is_bool)
192}
193
194/// Construct a [Number](crate::val::Number) [Value](crate::val::Value)
195#[unsafe(no_mangle)]
196pub extern "C" fn haystack_value_make_number(val: f64) -> Box<Value> {
197 Box::new(Value::make_number(val))
198}
199
200/// True if a [Number](crate::val::Number) [Value](crate::val::Value)
201/// # Arguments
202/// val a [Value](crate::val::Value).
203/// # Returns
204/// True, or False in which case if argument type mismatch an error is created that can be read using
205/// [last_error_message](super::err::last_error_message)
206/// # Example
207/// ```rust
208/// # use crate::libhaystack::val::Value;
209/// # use crate::libhaystack::c_api::value::*;
210/// let val = haystack_value_make_number(12.0);
211/// # unsafe {
212/// # let val = Box::<Value>::leak(val);
213/// assert!(!haystack_value_is_remove(val));
214/// assert!(haystack_value_is_number(val));
215/// # }
216/// ```
217/// # Safety
218/// Panics on invalid input data
219#[unsafe(no_mangle)]
220pub unsafe extern "C" fn haystack_value_is_number(val: *const Value) -> bool {
221 safe_bool_call!(val, is_number)
222}
223
224/// Construct a [Number](crate::val::Number) [Value](crate::val::Value) with an unit
225/// # Arguments
226/// - val a 64 bit double.
227/// - a C string for the unit
228/// # Returns
229/// A Number [Value](crate::val::Value), if argument type mismatch an error is created that can be read using
230/// [last_error_message](super::err::last_error_message)
231/// # Example
232/// ```rust
233/// # use crate::libhaystack::val::Value;
234/// # use crate::libhaystack::c_api::value::*;
235/// # unsafe {
236/// let unit = std::ffi::CString::new("sec").unwrap();
237/// let val = haystack_value_make_number_with_unit(42.0, unit.as_ptr());
238/// # let val = Box::<Value>::leak(val.unwrap());
239/// assert!(!haystack_value_is_null(val));
240/// assert!(haystack_value_is_number(val));
241/// # }
242/// ```
243/// # Safety
244/// Panics on invalid input data
245#[unsafe(no_mangle)]
246pub unsafe extern "C" fn haystack_value_make_number_with_unit(
247 val: f64,
248 unit: *const c_char,
249) -> Option<Box<Value>> {
250 if unit.is_null() {
251 new_error("Invalid null unit");
252 return None;
253 }
254 match unsafe { CStr::from_ptr(unit).to_str() } {
255 Ok(unit) => {
256 if let Some(unit) = get_unit(unit) {
257 Some(Box::new(Value::make_number_unit(val, unit)))
258 } else {
259 new_error(&format!("Invalid unit string. {unit}"));
260 None
261 }
262 }
263 Err(err) => {
264 new_error(&format!("Invalid unit string. {err}"));
265 None
266 }
267 }
268}
269
270/// Construct a [Coord](crate::val::Coord) [Value](crate::val::Value)
271#[unsafe(no_mangle)]
272pub extern "C" fn haystack_value_make_coord(lat: f64, long: f64) -> Box<Value> {
273 Box::new(Value::make_coord_from(lat, long))
274}
275
276/// True if a [Coord](crate::val::Coord) [Value](crate::val::Value)
277/// # Returns
278/// True, or False in which case if argument type mismatch an error is created that can be read using
279/// [last_error_message](super::err::last_error_message)
280/// # Example
281/// ```rust
282/// # use crate::libhaystack::val::Value;
283/// # use crate::libhaystack::c_api::value::*;
284/// let val = haystack_value_make_coord(1.0, 2.0);
285/// # unsafe {
286/// # let val = Box::<Value>::leak(val);
287/// assert!(!haystack_value_is_null(val));
288/// assert!(haystack_value_is_coord(val));
289/// # }
290/// ```
291/// # Safety
292/// Panics on invalid input data
293#[unsafe(no_mangle)]
294pub unsafe extern "C" fn haystack_value_is_coord(val: *const Value) -> bool {
295 safe_bool_call!(val, is_coord)
296}
297
298/// Construct a [Str](crate::val::Str) [Value](crate::val::Value)
299/// # Safety
300/// Panics on invalid input data
301#[unsafe(no_mangle)]
302pub unsafe extern "C" fn haystack_value_make_str(val: *const c_char) -> Option<Box<Value>> {
303 if val.is_null() {
304 new_error("Invalid null argument(s)");
305 return None;
306 }
307 match unsafe { CStr::from_ptr(val).to_str() } {
308 Ok(c_str) => Some(Box::new(Value::make_str(c_str))),
309 Err(err) => {
310 new_error(&format!("Invalid C string. {err}"));
311 None
312 }
313 }
314}
315
316/// True if a [Str](crate::val::Str) [Value](crate::val::Value)
317/// # Returns
318/// True, or False in which case if argument type mismatch an error is created that can be read using
319/// [last_error_message](super::err::last_error_message)
320/// # Example
321/// ```rust
322/// # use crate::libhaystack::val::Value;
323/// # use crate::libhaystack::c_api::value::*;
324/// # unsafe {
325/// let str = std::ffi::CString::new("foo bar").unwrap();
326/// let val = haystack_value_make_str(str.as_ptr());
327/// # let val = Box::<Value>::leak(val.unwrap());
328/// assert!(!haystack_value_is_null(val));
329/// assert!(haystack_value_is_str(val));
330/// # }
331/// ```
332/// # Safety
333/// Panics on invalid input data
334#[unsafe(no_mangle)]
335pub unsafe extern "C" fn haystack_value_is_str(val: *const Value) -> bool {
336 safe_bool_call!(val, is_str)
337}
338
339/// Construct a [Ref](crate::val::Ref) [Value](crate::val::Value)
340/// # Safety
341/// Panics on invalid input data
342#[unsafe(no_mangle)]
343pub unsafe extern "C" fn haystack_value_make_ref(val: *const c_char) -> Option<Box<Value>> {
344 if val.is_null() {
345 new_error("Invalid null argument(s)");
346 return None;
347 }
348 match unsafe { CStr::from_ptr(val).to_str() } {
349 Ok(c_str) => Some(Box::new(Value::make_ref(c_str))),
350 Err(err) => {
351 new_error(&format!("Invalid C string. {err}"));
352 None
353 }
354 }
355}
356
357/// Construct a [Ref](crate::val::Ref) [Value](crate::val::Value) with a display name
358/// # Safety
359/// Panics on invalid input data
360#[unsafe(no_mangle)]
361pub unsafe extern "C" fn haystack_value_make_ref_with_dis(
362 val: *const c_char,
363 dis: *const c_char,
364) -> Option<Box<Value>> {
365 if val.is_null() || dis.is_null() {
366 new_error("Invalid null argument(s)");
367 return None;
368 }
369 match unsafe { CStr::from_ptr(val).to_str() } {
370 Ok(id) => match unsafe { CStr::from_ptr(dis).to_str() } {
371 Ok(dis) => Some(Box::new(Value::make_ref_with_dis(id, dis))),
372 Err(err) => {
373 new_error(&format!("Invalid dis string. {err}"));
374 None
375 }
376 },
377 Err(err) => {
378 new_error(&format!("Invalid value string. {err}"));
379 None
380 }
381 }
382}
383
384/// True if a [Ref](crate::val::Ref) [Value](crate::val::Value)
385/// # Returns
386/// True, or False in which case if argument type mismatch an error is created that can be read using
387/// [last_error_message](super::err::last_error_message)
388/// # Example
389/// ```rust
390/// # use crate::libhaystack::val::Value;
391/// # use crate::libhaystack::c_api::value::*;
392/// # unsafe {
393/// let id = std::ffi::CString::new("someId_ofSomething").unwrap();
394/// let val = haystack_value_make_ref(id.as_ptr());
395/// # let val = Box::<Value>::leak(val.unwrap());
396/// assert!(!haystack_value_is_null(val));
397/// assert!(haystack_value_is_ref(val));
398/// # }
399/// ```
400/// # Safety
401/// Panics on invalid input data
402#[unsafe(no_mangle)]
403pub unsafe extern "C" fn haystack_value_is_ref(val: *const Value) -> bool {
404 safe_bool_call!(val, is_ref)
405}
406
407/// Construct a [Uri](crate::val::Uri) [Value](crate::val::Value)
408/// # Safety
409/// Panics on invalid input data
410#[unsafe(no_mangle)]
411pub unsafe extern "C" fn haystack_value_make_uri(val: *const c_char) -> Option<Box<Value>> {
412 if val.is_null() {
413 new_error("Invalid null argument(s)");
414 return None;
415 }
416 match unsafe { CStr::from_ptr(val).to_str() } {
417 Ok(c_str) => Some(Box::new(Value::make_uri(c_str))),
418 Err(err) => {
419 new_error(&format!("Invalid C string. {err}"));
420 None
421 }
422 }
423}
424
425/// True if a [Uri](crate::val::Uri) [Value](crate::val::Value)
426/// # Returns
427/// True, or False in which case if argument type mismatch an error is created that can be read using
428/// [last_error_message](super::err::last_error_message)
429/// # Example
430/// ```rust
431/// # use crate::libhaystack::val::Value;
432/// # use crate::libhaystack::c_api::value::*;
433/// # unsafe {
434/// let str = std::ffi::CString::new("/a/b/c").unwrap();
435/// let val = haystack_value_make_uri(str.as_ptr());
436/// # let val = Box::<Value>::leak(val.unwrap());
437/// assert!(!haystack_value_is_null(val));
438/// assert!(haystack_value_is_uri(val));
439/// # }
440/// ```
441/// # Safety
442/// Panics on invalid input data
443#[unsafe(no_mangle)]
444pub unsafe extern "C" fn haystack_value_is_uri(val: *const Value) -> bool {
445 safe_bool_call!(val, is_uri)
446}
447
448/// Construct a [Symbol](crate::val::Symbol) [Value](crate::val::Value)
449/// # Safety
450/// Panics on invalid input data
451#[unsafe(no_mangle)]
452pub unsafe extern "C" fn haystack_value_make_symbol(val: *const c_char) -> Option<Box<Value>> {
453 if val.is_null() {
454 new_error("Invalid null argument(s)");
455 return None;
456 }
457 match unsafe { CStr::from_ptr(val).to_str() } {
458 Ok(c_str) => Some(Box::new(Value::make_symbol(c_str))),
459 Err(err) => {
460 new_error(&format!("Invalid C string. {err}"));
461 None
462 }
463 }
464}
465
466/// True if a [Symbol](crate::val::Symbol) [Value](crate::val::Value)
467/// # Returns
468/// True, or False in which case if argument type mismatch an error is created that can be read using
469/// [last_error_message](super::err::last_error_message)
470/// # Example
471/// ```rust
472/// # use crate::libhaystack::val::Value;
473/// # use crate::libhaystack::c_api::value::*;
474/// # unsafe {
475/// let str = std::ffi::CString::new("def").unwrap();
476/// let val = haystack_value_make_symbol(str.as_ptr());
477/// # let val = Box::<Value>::leak(val.unwrap());
478/// assert!(!haystack_value_is_null(val));
479/// assert!(haystack_value_is_symbol(val));
480/// # }
481/// ```
482/// # Safety
483/// Panics on invalid input data
484#[unsafe(no_mangle)]
485pub unsafe extern "C" fn haystack_value_is_symbol(val: *const Value) -> bool {
486 safe_bool_call!(val, is_symbol)
487}
488
489/// Construct a [XStr](crate::val::XStr) [Value](crate::val::Value)
490/// # Safety
491/// Panics on invalid input data
492pub unsafe extern "C" fn haystack_value_make_xstr(
493 name: *const c_char,
494 data: *const c_char,
495) -> Option<Box<Value>> {
496 if name.is_null() || data.is_null() {
497 new_error("Invalid null argument(s)");
498 return None;
499 }
500 let args: Result<Vec<&str>, std::str::Utf8Error> = [name, data]
501 .iter()
502 .map(|e| unsafe { CStr::from_ptr(*e).to_str() })
503 .collect();
504
505 match args {
506 Ok(args) => Some(Box::new(Value::make_xstr_from(args[0], args[1]))),
507 Err(err) => {
508 new_error(&format!("Invalid C string arguments. {err}"));
509 None
510 }
511 }
512}
513
514/// True if a [XStr](crate::val::XStr) [Value](crate::val::Value)
515/// # Returns
516/// True, or False in which case if argument type mismatch an error is created that can be read using
517/// [last_error_message](super::err::last_error_message)
518/// # Example
519/// ```rust
520/// # use crate::libhaystack::val::Value;
521/// # use crate::libhaystack::c_api::value::*;
522/// # unsafe {
523/// let typ = std::ffi::CString::new("Foo").unwrap();
524/// let data = std::ffi::CString::new("bar").unwrap();
525/// let val = haystack_value_make_xstr(typ.as_ptr(), data.as_ptr());
526/// # let val = Box::<Value>::leak(val.unwrap());
527/// assert!(!haystack_value_is_null(val));
528/// assert!(haystack_value_is_xstr(val));
529/// # }
530/// ```
531/// # Safety
532/// Panics on invalid input data
533#[unsafe(no_mangle)]
534pub unsafe extern "C" fn haystack_value_is_xstr(val: *const Value) -> bool {
535 safe_bool_call!(val, is_xstr)
536}
537
538/// Construct a [Time](crate::val::Time) [Value](crate::val::Value)
539/// # Safety
540/// Panics on invalid input data
541#[unsafe(no_mangle)]
542pub extern "C" fn haystack_value_make_time(hour: u32, min: u32, sec: u32) -> Option<Box<Value>> {
543 match Time::from_hms(hour, min, sec) {
544 Ok(time) => Some(Box::new(Value::Time(time))),
545 Err(err) => {
546 new_error(&err);
547 None
548 }
549 }
550}
551
552/// Construct a [Time](crate::val::Time) [Value](crate::val::Value)
553#[unsafe(no_mangle)]
554pub extern "C" fn haystack_value_make_time_millis(
555 hour: u32,
556 min: u32,
557 sec: u32,
558 milli: u32,
559) -> Option<Box<Value>> {
560 match Time::from_hms_milli(hour, min, sec, milli) {
561 Ok(time) => Some(Box::new(Value::Time(time))),
562 Err(err) => {
563 new_error(&err);
564 None
565 }
566 }
567}
568
569/// True if a [Time](crate::val::Time) [Value](crate::val::Value)
570/// # Returns
571/// True, or False in which case if argument type mismatch an error is created that can be read using
572/// [last_error_message](super::err::last_error_message)
573/// # Example
574/// ```rust
575/// # use crate::libhaystack::val::Value;
576/// # use crate::libhaystack::c_api::value::*;
577/// # unsafe {
578/// let val = haystack_value_make_time(12, 12, 59);
579/// # let val = Box::<Value>::leak(val.unwrap());
580/// assert!(!haystack_value_is_null(val));
581/// assert!(haystack_value_is_time(val));
582/// # }
583/// ```
584/// # Safety
585/// Panics on invalid input data
586#[unsafe(no_mangle)]
587pub unsafe extern "C" fn haystack_value_is_time(val: *const Value) -> bool {
588 safe_bool_call!(val, is_time)
589}
590
591/// Construct a [Date](crate::val::Date) [Value](crate::val::Value)
592#[unsafe(no_mangle)]
593pub extern "C" fn haystack_value_make_date(year: i32, month: u32, day: u32) -> Option<Box<Value>> {
594 match Date::from_ymd(year, month, day) {
595 Ok(date) => Some(Box::new(Value::Date(date))),
596 Err(err) => {
597 new_error(&err);
598 None
599 }
600 }
601}
602
603/// True if a [Date](crate::val::Date) [Value](crate::val::Value)
604/// # Returns
605/// True, or False in which case if argument type mismatch an error is created that can be read using
606/// [last_error_message](super::err::last_error_message)
607/// # Example
608/// ```rust
609/// # use crate::libhaystack::val::Value;
610/// # use crate::libhaystack::c_api::value::*;
611/// # unsafe {
612/// let val = haystack_value_make_date(2021, 8, 13);
613/// # let val = Box::<Value>::leak(val.unwrap());
614/// assert!(!haystack_value_is_null(val));
615/// assert!(haystack_value_is_date(val));
616/// # }
617/// ```
618/// # Safety
619/// Panics on invalid input data
620#[unsafe(no_mangle)]
621pub unsafe extern "C" fn haystack_value_is_date(val: *const Value) -> bool {
622 safe_bool_call!(val, is_date)
623}
624
625/// Construct a UTC [DateTime](crate::val::DateTime) [Value](crate::val::Value)
626/// # Safety
627/// Panics on invalid input data
628#[unsafe(no_mangle)]
629pub extern "C" fn haystack_value_make_utc_datetime(
630 date: *mut Value,
631 time: *mut Value,
632) -> Option<Box<Value>> {
633 if date.is_null() || time.is_null() {
634 new_error("Invalid null argument(s)");
635 return None;
636 }
637 let args: Vec<&Value> = [date, time]
638 .iter()
639 .filter_map(|e| unsafe { e.as_ref() })
640 .enumerate()
641 .filter(|(idx, val)| *idx == 0 && val.is_date() || *idx == 1 && val.is_time())
642 .map(|e| e.1)
643 .collect();
644
645 if args.len() != 2 {
646 new_error("Invalid null argument(s)");
647 return None;
648 }
649
650 let (date, time) = (
651 Date::try_from(args[0]).expect("Date"),
652 Time::try_from(args[1]).expect("Time"),
653 );
654
655 let datetime = NaiveDateTime::new(*date, *time);
656 let utc = Utc.from_utc_datetime(&datetime);
657
658 Some(Box::new(Value::make_datetime(utc.into())))
659}
660
661/// Construct a Timezone [DateTime](crate::val::DateTime) [Value](crate::val::Value)
662/// # Safety
663/// Panics on invalid input data
664#[cfg(feature = "timezone")]
665#[unsafe(no_mangle)]
666pub unsafe extern "C" fn haystack_value_make_tz_datetime(
667 date: *mut Value,
668 time: *mut Value,
669 tz: *const c_char,
670) -> Option<Box<Value>> {
671 use crate::haystack::timezone::make_date_time_with_tz;
672 use crate::haystack::val::DateTime;
673 use chrono::Offset;
674
675 let datetime = haystack_value_make_utc_datetime(date, time);
676
677 if datetime.is_none() || tz.is_null() {
678 new_error("Invalid null argument(s)");
679 return None;
680 }
681
682 if let Ok(datetime) = if let Some(datetime) = datetime {
683 DateTime::try_from(datetime.as_ref())
684 } else {
685 Err("")
686 } {
687 match unsafe { CStr::from_ptr(tz).to_str() } {
688 Ok(tz) => match make_date_time_with_tz(&datetime.with_timezone(&Utc.fix()), tz) {
689 Ok(datetime) => Some(Box::new(Value::DateTime(datetime.into()))),
690 Err(err) => {
691 new_error(&err);
692 None
693 }
694 },
695 Err(err) => {
696 new_error(&format!("Invalid timezone string. {err}"));
697 None
698 }
699 }
700 } else {
701 new_error("Invalid datetime");
702 None
703 }
704}
705
706/// True if a [DateTime](crate::val::DateTime) [Value](crate::val::Value)
707/// # Returns
708/// True, or False in which case if argument type mismatch an error is created that can be read using
709/// [last_error_message](super::err::last_error_message)
710/// # Example
711/// ```rust
712/// # use crate::libhaystack::val::Value;
713/// # use crate::libhaystack::c_api::value::*;
714/// # unsafe {
715/// let date = haystack_value_make_date(2021, 8, 13);
716/// let time = haystack_value_make_time(9, 45, 59);
717/// # let date = Box::<Value>::leak(date.unwrap());
718/// # let time = Box::<Value>::leak(time.unwrap());
719/// let tz = std::ffi::CString::new("UTC").unwrap();
720/// let val = haystack_value_make_tz_datetime(date, time, tz.as_ptr());
721/// # let val = Box::<Value>::leak(val.unwrap());
722/// assert!(!haystack_value_is_null(val));
723/// assert!(haystack_value_is_datetime(val));
724/// # }
725/// ```
726/// # Safety
727/// Panics on invalid input data
728#[unsafe(no_mangle)]
729pub unsafe extern "C" fn haystack_value_is_datetime(val: *const Value) -> bool {
730 safe_bool_call!(val, is_datetime)
731}
732
733/// Construct a empty [List](crate::val::List) [Value](crate::val::Value)
734/// # Safety
735/// Panics on invalid input data
736#[unsafe(no_mangle)]
737pub extern "C" fn haystack_value_make_list() -> Box<Value> {
738 Box::new(Value::make_list(List::new()))
739}
740
741/// True if a [List](crate::val::List) [Value](crate::val::Value)
742/// # Returns
743/// True, or False in which case if argument type mismatch an error is created that can be read using
744/// [last_error_message](super::err::last_error_message)
745/// # Example
746/// ```rust
747/// # use crate::libhaystack::val::Value;
748/// # use crate::libhaystack::c_api::value::*;
749/// # unsafe {
750/// let val = haystack_value_make_list();
751/// # let val = Box::<Value>::leak(val);
752/// assert!(!haystack_value_is_null(val));
753/// assert!(haystack_value_is_list(val));
754/// # }
755/// ```
756/// # Safety
757/// Panics on invalid input data
758#[unsafe(no_mangle)]
759pub unsafe extern "C" fn haystack_value_is_list(val: *const Value) -> bool {
760 safe_bool_call!(val, is_list)
761}
762
763/// Construct an empty [Dict](crate::val::Dict) [Value](crate::val::Value)
764#[unsafe(no_mangle)]
765pub extern "C" fn haystack_value_make_dict() -> Box<Value> {
766 Box::new(Value::make_dict(Dict::new()))
767}
768
769/// True if a [Dict](crate::val::Dict) [Value](crate::val::Value)
770/// # Returns
771/// True, or False in which case if argument type mismatch an error is created that can be read using
772/// [last_error_message](super::err::last_error_message)
773/// # Example
774/// ```rust
775/// # use crate::libhaystack::val::Value;
776/// # use crate::libhaystack::c_api::value::*;
777/// # unsafe {
778/// let val = haystack_value_make_dict();
779/// # let val = Box::<Value>::leak(val);
780/// assert!(!haystack_value_is_null(val));
781/// assert!(haystack_value_is_dict(val));
782/// # }
783/// ```
784/// # Safety
785/// Panics on invalid input data
786#[unsafe(no_mangle)]
787pub unsafe extern "C" fn haystack_value_is_dict(val: *const Value) -> bool {
788 safe_bool_call!(val, is_dict)
789}
790
791/// Construct an empty [Grid](crate::val::Grid) [Value](crate::val::Value)
792/// # Safety
793/// Panics on invalid input data
794#[unsafe(no_mangle)]
795pub extern "C" fn haystack_value_make_grid() -> Box<Value> {
796 Box::new(Value::make_grid(Grid::make_empty()))
797}
798
799/// True if a [Grid](crate::val::Grid) [Value](crate::val::Value)
800/// # Returns
801/// True, or False in which case if argument type mismatch an error is created that can be read using
802/// [last_error_message](super::err::last_error_message)
803/// # Example
804/// ```rust
805/// # use crate::libhaystack::val::Value;
806/// # use crate::libhaystack::c_api::value::*;
807/// # unsafe {
808/// let val = haystack_value_make_grid();
809/// # let val = Box::<Value>::leak(val);
810/// assert!(!haystack_value_is_null(val));
811/// assert!(haystack_value_is_grid(val));
812/// # }
813/// ```
814/// # Safety
815/// Panics on invalid input data
816#[unsafe(no_mangle)]
817pub unsafe extern "C" fn haystack_value_is_grid(val: *const Value) -> bool {
818 safe_bool_call!(val, is_grid)
819}