cel_cxx_ffi/
absl.rs

1use std::borrow::Cow;
2
3use crate::Rep;
4
5#[cxx::bridge]
6mod ffi {
7    #[namespace = "absl"]
8    unsafe extern "C++" {
9        include!(<absl/time/time.h>);
10
11        type Duration = super::Duration;
12        fn Nanoseconds(n: i64) -> Duration;
13        fn ToInt64Nanoseconds(duration: Duration) -> i64;
14
15        type Time = super::Timestamp;
16        fn ToUnixNanos(time: Time) -> i64;
17        fn FromUnixNanos(nanos: i64) -> Time;
18
19        include!(<absl/status/status.h>);
20        type StatusCode = super::StatusCode;
21
22        type Status = super::Status;
23        #[rust_name = "is_ok"]
24        fn ok(self: &Status) -> bool;
25        fn code(self: &Status) -> StatusCode;
26        fn message<'a>(self: &'a Status) -> string_view<'a>;
27
28        fn OkStatus() -> Status;
29        fn IsAborted(status: &Status) -> bool;
30        fn IsAlreadyExists(status: &Status) -> bool;
31        fn IsCancelled(status: &Status) -> bool;
32        fn IsDataLoss(status: &Status) -> bool;
33        fn IsDeadlineExceeded(status: &Status) -> bool;
34        fn IsFailedPrecondition(status: &Status) -> bool;
35        fn IsInternal(status: &Status) -> bool;
36        fn IsInvalidArgument(status: &Status) -> bool;
37        fn IsNotFound(status: &Status) -> bool;
38        fn IsOutOfRange(status: &Status) -> bool;
39        fn IsPermissionDenied(status: &Status) -> bool;
40        fn IsResourceExhausted(status: &Status) -> bool;
41        fn IsUnauthenticated(status: &Status) -> bool;
42        fn IsUnavailable(status: &Status) -> bool;
43        fn IsUnimplemented(status: &Status) -> bool;
44        fn IsUnknown(status: &Status) -> bool;
45
46        fn AbortedError(msg: string_view) -> Status;
47        fn AlreadyExistsError(msg: string_view) -> Status;
48        fn CancelledError(msg: string_view) -> Status;
49        fn DataLossError(msg: string_view) -> Status;
50        fn DeadlineExceededError(msg: string_view) -> Status;
51        fn FailedPreconditionError(msg: string_view) -> Status;
52        fn InternalError(msg: string_view) -> Status;
53        fn InvalidArgumentError(msg: string_view) -> Status;
54        fn NotFoundError(msg: string_view) -> Status;
55        fn OutOfRangeError(msg: string_view) -> Status;
56        fn PermissionDeniedError(msg: string_view) -> Status;
57        fn ResourceExhaustedError(msg: string_view) -> Status;
58        fn UnauthenticatedError(msg: string_view) -> Status;
59        fn UnavailableError(msg: string_view) -> Status;
60        fn UnimplementedError(msg: string_view) -> Status;
61        fn UnknownError(msg: string_view) -> Status;
62
63        include!(<absl/strings/string_view.h>);
64        #[allow(unused, non_camel_case_types)]
65        type string_view<'a> = super::StringView<'a>;
66        #[rust_name = "len"]
67        fn size(self: &string_view) -> usize;
68        fn data(self: &string_view) -> *const c_char;
69    }
70
71    #[namespace = "absl"]
72    unsafe extern "C++" {
73        include!(<absl/log/log_entry.h>);
74        
75        type LogSeverity = super::log::LogSeverity;
76        type LogSeverityAtLeast = super::log::LogSeverityAtLeast;
77        
78        type LogEntry;
79        // LogEntry accessor methods
80        fn log_severity(self: &LogEntry) -> LogSeverity;
81        fn text_message<'a>(self: &'a LogEntry) -> string_view<'a>;
82        fn source_filename<'a>(self: &'a LogEntry) -> string_view<'a>;
83        //fn source_basename<'a>(self: &'a LogEntry) -> string_view<'a>;
84        fn source_line(self: &LogEntry) -> i32;
85
86        include!(<absl/log/globals.h>);
87        #[rust_name = "set_stderr_threshold"]
88        fn SetStderrThreshold(severity: LogSeverityAtLeast);
89    }
90
91    #[namespace = "rust::cel_cxx"]
92    unsafe extern "C++" {
93        include!(<cel-cxx-ffi/include/absl.h>);
94
95        fn Duration_new(seconds: i64, nanos: u32) -> Duration;
96        fn Duration_seconds(duration: Duration) -> i64;
97        fn Duration_nanos(duration: Duration) -> u32;
98
99        fn Timestamp_new(seconds: i64, nanos: u32) -> Time;
100        fn Timestamp_seconds(timestamp: Time) -> i64;
101        fn Timestamp_nanos(timestamp: Time) -> u32;
102
103        fn StringView_new<'a>(bytes: &'a [u8]) -> string_view<'a>;
104
105        fn StatusCode_to_string(code: StatusCode) -> String;
106
107        fn Status_new(code: StatusCode, msg: &str) -> Status;
108        fn Status_clone(status: &Status) -> Status;
109        fn Status_drop(status: &mut Status);
110        fn Status_to_string(status: &Status) -> String;
111        
112        #[rust_name = "initialize_log"]
113        fn InitializeLog();
114
115        #[rust_name = "set_log_callback"]
116        fn SetLogCallback();
117    }
118
119    #[namespace = "rust::cel_cxx"]
120    extern "Rust" {
121        #[cxx_name = "LogCallback"]
122        fn log_callback(entry: &LogEntry);
123    }
124}
125
126use log::log_callback;
127pub mod log {
128    use super::ffi;
129    use std::sync::Once;
130
131    #[allow(dead_code)]
132    #[repr(i32)]
133    #[derive(Copy, Clone)]
134    pub(super) enum LogSeverity {
135        Info = 0,
136        Warning = 1,
137        Error = 2,
138        Fatal = 3,
139    }
140    unsafe impl cxx::ExternType for LogSeverity {
141        type Id = cxx::type_id!("absl::LogSeverity");
142        type Kind = cxx::kind::Trivial;
143    }
144
145    #[allow(dead_code)]
146    #[repr(i32)]
147    #[derive(Copy, Clone)]
148    pub(super) enum LogSeverityAtLeast {
149        Info = 0,
150        Warning = 1,
151        Error = 2,
152        Fatal = 3,
153        Infinity = 1000,
154    }
155    unsafe impl cxx::ExternType for LogSeverityAtLeast {
156        type Id = cxx::type_id!("absl::LogSeverityAtLeast");
157        type Kind = cxx::kind::Trivial;
158    }
159    
160    static ONCE: Once = Once::new();
161    
162    /// Initialize absl log system and bridge to Rust log
163    /// This function is idempotent and can be called multiple times safely
164    pub fn init() {
165        ONCE.call_once(|| {
166            ffi::initialize_log();
167
168            ffi::set_log_callback();
169
170            ffi::set_stderr_threshold(LogSeverityAtLeast::Infinity);
171        });
172    }
173    
174    /// Log callback function - converts absl::LogEntry to log::Record
175    pub(super) fn log_callback(entry: &ffi::LogEntry) {
176        // Convert absl log severity to log::Level
177        let level = match entry.log_severity() {
178            LogSeverity::Info => log::Level::Info,
179            LogSeverity::Warning => log::Level::Warn,
180            LogSeverity::Error => log::Level::Error,
181            LogSeverity::Fatal => log::Level::Error,
182        };
183        
184        // Extract message and file information
185        let message = entry.text_message().to_string_lossy();
186        let file = entry.source_filename().to_string_lossy();
187        let line = entry.source_line();
188        
189        // Create and log the record
190        log::logger().log(
191            &log::Record::builder()
192                .args(format_args!("{message}"))
193                .level(level)
194                .file(Some(file.as_ref()))
195                .line(if line > 0 { Some(line as u32) } else { None })
196                .build()
197        );
198    }
199}
200
201#[repr(transparent)]
202#[derive(Copy, Clone)]
203pub struct Duration(Rep<'static, u32, 3>);
204
205unsafe impl cxx::ExternType for Duration {
206    type Id = cxx::type_id!("absl::Duration");
207    type Kind = cxx::kind::Trivial;
208}
209
210impl Duration {
211    pub fn new(seconds: i64, nanos: u32) -> Self {
212        ffi::Duration_new(seconds, nanos)
213    }
214
215    pub fn from_nanos(nanos: i64) -> Self {
216        ffi::Nanoseconds(nanos)
217    }
218
219    pub fn to_nanos(&self) -> i64 {
220        ffi::ToInt64Nanoseconds(*self)
221    }
222
223    pub fn seconds(&self) -> i64 {
224        ffi::Duration_seconds(*self)
225    }
226
227    pub fn nanos(&self) -> u32 {
228        ffi::Duration_nanos(*self)
229    }
230}
231
232impl From<chrono::Duration> for Duration {
233    fn from(value: chrono::Duration) -> Self {
234        Self::new(value.num_seconds(), value.subsec_nanos() as u32)
235    }
236}
237
238impl From<Duration> for chrono::Duration {
239    fn from(value: Duration) -> Self {
240        Self::new(value.seconds(), value.nanos()).unwrap_or_default()
241    }
242}
243
244#[repr(transparent)]
245#[derive(Copy, Clone)]
246pub struct Timestamp(Rep<'static, u32, 3>);
247
248unsafe impl cxx::ExternType for Timestamp {
249    type Id = cxx::type_id!("absl::Time");
250    type Kind = cxx::kind::Trivial;
251}
252
253impl Timestamp {
254    pub fn new(seconds: i64, nanos: u32) -> Self {
255        ffi::Timestamp_new(seconds, nanos)
256    }
257
258    pub fn from_unix_nanos(nanos: i64) -> Self {
259        ffi::FromUnixNanos(nanos)
260    }
261
262    pub fn unix_nanos(&self) -> i64 {
263        ffi::ToUnixNanos(*self)
264    }
265
266    pub fn seconds(&self) -> i64 {
267        ffi::Timestamp_seconds(*self)
268    }
269
270    pub fn nanos(&self) -> u32 {
271        ffi::Timestamp_nanos(*self)
272    }
273}
274
275impl From<chrono::DateTime<chrono::Utc>> for Timestamp {
276    fn from(value: chrono::DateTime<chrono::Utc>) -> Self {
277        Self::new(value.timestamp(), value.timestamp_subsec_nanos())
278    }
279}
280
281impl From<Timestamp> for chrono::DateTime<chrono::Utc> {
282    fn from(value: Timestamp) -> Self {
283        Self::from_timestamp(value.seconds(), value.nanos()).unwrap_or_default()
284    }
285}
286
287// absl::StatusCode
288#[repr(i32)]
289#[derive(Copy, Clone)]
290pub enum StatusCode {
291    Ok = 0,
292    Cancelled = 1,
293    Unknown = 2,
294    InvalidArgument = 3,
295    DeadlineExceeded = 4,
296    NotFound = 5,
297    AlreadyExists = 6,
298    PermissionDenied = 7,
299    ResourceExhausted = 8,
300    FailedPrecondition = 9,
301    Aborted = 10,
302    OutOfRange = 11,
303    Unimplemented = 12,
304    Internal = 13,
305    Unavailable = 14,
306    DataLoss = 15,
307    Unauthenticated = 16,
308}
309
310unsafe impl cxx::ExternType for StatusCode {
311    type Id = cxx::type_id!("absl::StatusCode");
312    type Kind = cxx::kind::Trivial;
313}
314
315impl std::fmt::Display for StatusCode {
316    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317        let string = ffi::StatusCode_to_string(*self);
318        write!(f, "{string}")
319    }
320}
321
322// absl::Status
323#[repr(transparent)]
324pub struct Status(Rep<'static, usize, 1>);
325
326unsafe impl cxx::ExternType for Status {
327    type Id = cxx::type_id!("absl::Status");
328    type Kind = cxx::kind::Trivial;
329}
330
331impl Clone for Status {
332    fn clone(&self) -> Self {
333        ffi::Status_clone(self)
334    }
335}
336
337impl Drop for Status {
338    fn drop(&mut self) {
339        ffi::Status_drop(self)
340    }
341}
342
343impl Default for Status {
344    fn default() -> Self {
345        ffi::OkStatus()
346    }
347}
348
349impl std::fmt::Display for Status {
350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351        let string = ffi::Status_to_string(self);
352        write!(f, "{string}")
353    }
354}
355
356impl std::fmt::Debug for Status {
357    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358        let string = ffi::Status_to_string(self);
359        write!(f, "{string}")
360    }
361}
362
363impl std::error::Error for Status {}
364
365impl Status {
366    pub fn new(code: StatusCode, message: &str) -> Self {
367        ffi::Status_new(code, message)
368    }
369
370    pub fn ok() -> Self {
371        ffi::OkStatus()
372    }
373
374    pub fn is_aborted(&self) -> bool {
375        ffi::IsAborted(self)
376    }
377
378    pub fn is_already_exists(&self) -> bool {
379        ffi::IsAlreadyExists(self)
380    }
381
382    pub fn is_cancelled(&self) -> bool {
383        ffi::IsCancelled(self)
384    }
385
386    pub fn is_data_loss(&self) -> bool {
387        ffi::IsDataLoss(self)
388    }
389
390    pub fn is_deadline_exceeded(&self) -> bool {
391        ffi::IsDeadlineExceeded(self)
392    }
393
394    pub fn is_failed_precondition(&self) -> bool {
395        ffi::IsFailedPrecondition(self)
396    }
397
398    pub fn is_internal(&self) -> bool {
399        ffi::IsInternal(self)
400    }
401
402    pub fn is_invalid_argument(&self) -> bool {
403        ffi::IsInvalidArgument(self)
404    }
405
406    pub fn is_not_found(&self) -> bool {
407        ffi::IsNotFound(self)
408    }
409
410    pub fn is_out_of_range(&self) -> bool {
411        ffi::IsOutOfRange(self)
412    }
413
414    pub fn is_permission_denied(&self) -> bool {
415        ffi::IsPermissionDenied(self)
416    }
417
418    pub fn is_resource_exhausted(&self) -> bool {
419        ffi::IsResourceExhausted(self)
420    }
421
422    pub fn is_unauthenticated(&self) -> bool {
423        ffi::IsUnauthenticated(self)
424    }
425
426    pub fn is_unavailable(&self) -> bool {
427        ffi::IsUnavailable(self)
428    }
429
430    pub fn is_unimplemented(&self) -> bool {
431        ffi::IsUnimplemented(self)
432    }
433
434    pub fn is_unknown(&self) -> bool {
435        ffi::IsUnknown(self)
436    }
437
438    pub fn aborted(msg: &str) -> Self {
439        ffi::AbortedError(StringView::new_str(msg))
440    }
441
442    pub fn already_exists(msg: &str) -> Self {
443        ffi::AlreadyExistsError(StringView::new_str(msg))
444    }
445
446    pub fn cancelled(msg: &str) -> Self {
447        ffi::CancelledError(StringView::new_str(msg))
448    }
449
450    pub fn data_loss(msg: &str) -> Self {
451        ffi::DataLossError(StringView::new_str(msg))
452    }
453
454    pub fn deadline_exceeded(msg: &str) -> Self {
455        ffi::DeadlineExceededError(StringView::new_str(msg))
456    }
457
458    pub fn failed_precondition(msg: &str) -> Self {
459        ffi::FailedPreconditionError(StringView::new_str(msg))
460    }
461
462    pub fn internal(msg: &str) -> Self {
463        ffi::InternalError(StringView::new_str(msg))
464    }
465
466    pub fn invalid_argument(msg: &str) -> Self {
467        ffi::InvalidArgumentError(StringView::new_str(msg))
468    }
469
470    pub fn not_found(msg: &str) -> Self {
471        ffi::NotFoundError(StringView::new_str(msg))
472    }
473
474    pub fn out_of_range(msg: &str) -> Self {
475        ffi::OutOfRangeError(StringView::new_str(msg))
476    }
477
478    pub fn permission_denied(msg: &str) -> Self {
479        ffi::PermissionDeniedError(StringView::new_str(msg))
480    }
481
482    pub fn resource_exhausted(msg: &str) -> Self {
483        ffi::ResourceExhaustedError(StringView::new_str(msg))
484    }
485
486    pub fn unauthenticated(msg: &str) -> Self {
487        ffi::UnauthenticatedError(StringView::new_str(msg))
488    }
489
490    pub fn unavailable(msg: &str) -> Self {
491        ffi::UnavailableError(StringView::new_str(msg))
492    }
493
494    pub fn unimplemented(msg: &str) -> Self {
495        ffi::UnimplementedError(StringView::new_str(msg))
496    }
497
498    pub fn unknown(msg: &str) -> Self {
499        ffi::UnknownError(StringView::new_str(msg))
500    }
501}
502
503// absl::Span
504#[repr(C)]
505pub struct Span<'a, T: 'a + SpanElement> {
506    ptr: *const T,
507    len: usize,
508    _marker: std::marker::PhantomData<&'a T>,
509}
510
511impl<'a, T: 'a + SpanElement> Copy for Span<'a, T> {}
512impl<'a, T: 'a + SpanElement> Clone for Span<'a, T> {
513    fn clone(&self) -> Self {
514        *self
515    }
516}
517
518unsafe impl<'a, T: 'a + SpanElement> cxx::ExternType for Span<'a, T> {
519    type Id = T::TypeId;
520    type Kind = cxx::kind::Trivial;
521}
522
523impl<'a, T: 'a + SpanElement> Span<'a, T> {
524    pub fn len(&self) -> usize {
525        self.len
526    }
527
528    pub fn is_empty(&self) -> bool {
529        self.len == 0
530    }
531
532    pub fn get(&self, index: usize) -> Option<&'a T> {
533        if index < self.len() {
534            let offset = index * T::size_of();
535            unsafe { self.ptr.byte_add(offset).as_ref() }
536        } else {
537            None
538        }
539    }
540
541    pub fn iter(&self) -> SpanIter<'a, T> {
542        SpanIter {
543            span: *self,
544            index: 0,
545        }
546    }
547}
548
549impl<'a, T: 'a + SpanElement + cxx::ExternType<Kind = cxx::kind::Trivial>> Span<'a, T> {
550    pub fn from_slice(slice: &'a [T]) -> Self {
551        Self {
552            ptr: slice.as_ptr(),
553            len: slice.len(),
554            _marker: std::marker::PhantomData,
555        }
556    }
557
558    pub fn as_slice(&self) -> &'a [T] {
559        unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
560    }
561}
562
563pub struct SpanIter<'a, T: 'a + SpanElement> {
564    span: Span<'a, T>,
565    index: usize,
566}
567
568impl<'a, T: 'a + SpanElement> std::iter::Iterator for SpanIter<'a, T> {
569    type Item = &'a T;
570
571    fn next(&mut self) -> Option<Self::Item> {
572        if let Some(item) = self.span.get(self.index) {
573            self.index += 1;
574            Some(item)
575        } else {
576            None
577        }
578    }
579
580    fn size_hint(&self) -> (usize, Option<usize>) {
581        (
582            self.span.len() - self.index,
583            Some(self.span.len() - self.index),
584        )
585    }
586}
587
588impl<'a, T: 'a + SpanElement> std::iter::FusedIterator for SpanIter<'a, T> {}
589
590impl<'a, T: 'a + SpanElement> std::iter::ExactSizeIterator for SpanIter<'a, T> {}
591
592impl<'a, T: 'a + SpanElement> std::iter::IntoIterator for Span<'a, T> {
593    type Item = &'a T;
594    type IntoIter = SpanIter<'a, T>;
595
596    fn into_iter(self) -> Self::IntoIter {
597        SpanIter {
598            span: self,
599            index: 0,
600        }
601    }
602}
603
604impl<'a, T: 'a + SpanElement + std::fmt::Debug> std::fmt::Debug for Span<'a, T> {
605    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
606        f.debug_list().entries(self.iter()).finish()
607    }
608}
609
610pub trait SpanElement: crate::SizedExternType {
611    type TypeId;
612}
613
614// absl::string_view
615#[repr(C)]
616#[derive(Copy, Clone)]
617pub struct StringView<'a>(Rep<'a, usize, 2>);
618
619unsafe impl<'a> cxx::ExternType for StringView<'a> {
620    type Id = cxx::type_id!("absl::string_view");
621    type Kind = cxx::kind::Trivial;
622}
623
624impl<'a> crate::SizedExternType for StringView<'a> {}
625
626impl<'a> SpanElement for StringView<'a> {
627    type TypeId = cxx::type_id!("rust::cel_cxx::Span_StringView");
628}
629
630impl<'a> StringView<'a> {
631    pub fn new(bytes: &'a [u8]) -> Self {
632        ffi::StringView_new(bytes)
633    }
634
635    pub fn new_str(s: &'a str) -> Self {
636        Self::new(s.as_bytes())
637    }
638
639    pub fn is_empty(&self) -> bool {
640        self.len() == 0
641    }
642
643    pub fn as_bytes(&self) -> &'a [u8] {
644        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
645    }
646
647    pub fn to_str(&self) -> Result<&'a str, std::str::Utf8Error> {
648        std::str::from_utf8(self.as_bytes())
649    }
650
651    pub fn to_string_lossy(&self) -> Cow<'a, str> {
652        String::from_utf8_lossy(self.as_bytes())
653    }
654
655    pub fn as_ptr(&self) -> *const u8 {
656        self.data() as *const u8
657    }
658}