1mod ilp;
26mod op_state;
27
28#[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
29mod qwp;
30
31use crate::ingress::ndarr::ArrayElementSealed;
32use crate::ingress::{ArrayElement, DecimalView, NdArrayView, ProtocolVersion, Timestamp};
33use crate::{Error, error};
34use std::sync::atomic::{AtomicU64, Ordering};
35
36pub(crate) use self::ilp::Buffer as IlpBuffer;
37#[allow(unused_imports)]
38pub(crate) use self::ilp::F64Serializer;
39
40#[cfg(all(feature = "_sender-qwp-ws", feature = "arrow-ingress"))]
41pub(crate) use self::qwp::QWP_DECIMAL_MAX_SCALE;
42#[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
43pub(crate) use self::qwp::QwpBuffer;
44#[cfg(feature = "_sender-qwp-udp")]
45pub(crate) use self::qwp::QwpSendScratch;
46#[cfg(feature = "_sender-qwp-ws")]
47pub(crate) use self::qwp::{
48 MAX_PERSISTED_SYMBOL_ENTRY_LEN, QwpWsColumnarBuffer, QwpWsEncodeScratch, SymbolGlobalDict,
49 SymbolGlobalDictMark, decode_qwp_varint,
50};
51#[cfg(all(test, feature = "_sender-qwp-ws"))]
54pub(crate) use self::qwp::TestDictCapGuard;
55#[cfg(feature = "arrow-ingress")]
59pub(crate) use self::qwp::QwpWsSymbolHasher;
60
61static NEXT_BOOKMARK_ORIGIN: AtomicU64 = AtomicU64::new(1);
62
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
65pub struct Bookmark {
66 origin: u64,
67 generation: u64,
68}
69
70impl Bookmark {
71 #[doc(hidden)]
76 pub const fn from_raw(origin: u64, generation: u64) -> Self {
77 Self { origin, generation }
78 }
79
80 #[doc(hidden)]
84 pub const fn origin(self) -> u64 {
85 self.origin
86 }
87
88 #[doc(hidden)]
92 pub const fn generation(self) -> u64 {
93 self.generation
94 }
95}
96
97#[derive(Clone, Copy, Debug)]
98pub(super) struct BufferBookmarkMeta {
99 origin: u64,
100}
101
102impl BufferBookmarkMeta {
103 pub(super) fn new() -> Self {
104 Self {
105 origin: NEXT_BOOKMARK_ORIGIN.fetch_add(1, Ordering::Relaxed),
106 }
107 }
108
109 pub(super) const fn origin(self) -> u64 {
110 self.origin
111 }
112}
113
114#[derive(Clone, Copy, Debug)]
115pub(super) struct StoredBookmark<S: Copy> {
116 generation: u64,
117 state: Option<S>,
118}
119
120impl<S: Copy> StoredBookmark<S> {
121 pub(super) const fn new() -> Self {
122 Self {
123 generation: 0,
124 state: None,
125 }
126 }
127
128 pub(super) fn capture(&mut self, origin: u64, state: S) -> Bookmark {
129 self.generation = self.generation.wrapping_add(1);
130 if self.generation == 0 {
131 self.generation = 1;
132 }
133 self.state = Some(state);
134 Bookmark::from_raw(origin, self.generation)
135 }
136
137 pub(super) const fn current(&self) -> Option<S> {
138 self.state
139 }
140
141 pub(super) fn restore(&self, origin: u64, bookmark: Bookmark) -> crate::Result<S> {
142 if bookmark.origin() != origin {
143 return Err(error::fmt!(
144 InvalidApiCall,
145 "Can't rewind to the bookmark: Bookmark does not belong to this buffer."
146 ));
147 }
148 if self.state.is_none() && self.generation == 0 {
149 return Err(error::fmt!(
153 InvalidApiCall,
154 "Can't rewind to the bookmark: No bookmark set."
155 ));
156 }
157 match self.state {
158 Some(state) if self.generation == bookmark.generation() => Ok(state),
159 _ => Err(error::fmt!(
160 InvalidApiCall,
161 "Can't rewind to the bookmark: Bookmark is stale."
162 )),
163 }
164 }
165
166 pub(super) fn clear_if_matches(&mut self, origin: u64, bookmark: Bookmark) -> bool {
167 if bookmark.origin() == 0 {
168 return false;
169 }
170 if bookmark.origin() != origin {
171 debug_assert_eq!(
175 bookmark.origin(),
176 origin,
177 "attempted to clear a bookmark from a different buffer"
178 );
179 return false;
180 }
181 if self.state.is_some() && self.generation == bookmark.generation() {
182 self.state = None;
183 return true;
184 }
185 false
186 }
187
188 pub(super) fn clear(&mut self) {
189 self.state = None;
190 }
191}
192
193#[derive(Clone, Copy)]
200pub struct TableName<'a> {
201 name: &'a str,
202}
203
204impl<'a> TableName<'a> {
205 pub fn new(name: &'a str) -> crate::Result<Self> {
207 if name.is_empty() {
208 return Err(error::fmt!(
209 InvalidName,
210 "Table names must have a non-zero length."
211 ));
212 }
213
214 let mut prev = '\0';
215 for (byte_idx, c) in name.char_indices() {
216 match c {
217 '.' if byte_idx == 0 || byte_idx + c.len_utf8() == name.len() || prev == '.' => {
218 return Err(error::fmt!(
219 InvalidName,
220 concat!("Bad string {:?}: ", "Found invalid dot `.` at position {}."),
221 name,
222 byte_idx
223 ));
224 }
225 '.' => {}
226 '?' | ',' | '\'' | '\"' | '\\' | '/' | ':' | ')' | '(' | '+' | '*' | '%' | '~'
227 | '\r' | '\n' | '\0' | '\u{0001}' | '\u{0002}' | '\u{0003}' | '\u{0004}'
228 | '\u{0005}' | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{0009}' | '\u{000b}'
229 | '\u{000c}' | '\u{000e}' | '\u{000f}' | '\u{007f}' => {
230 return Err(error::fmt!(
231 InvalidName,
232 concat!(
233 "Bad string {:?}: ",
234 "Table names can't contain ",
235 "a {:?} character, which was found at ",
236 "byte position {}."
237 ),
238 name,
239 c,
240 byte_idx
241 ));
242 }
243 '\u{feff}' => {
244 return Err(error::fmt!(
247 InvalidName,
248 concat!(
249 "Bad string {:?}: ",
250 "Table names can't contain ",
251 "a UTF-8 BOM character, which was found at ",
252 "byte position {}."
253 ),
254 name,
255 byte_idx
256 ));
257 }
258 _ => (),
259 }
260 prev = c;
261 }
262
263 Ok(Self { name })
264 }
265
266 pub fn new_unchecked(name: &'a str) -> Self {
273 Self { name }
274 }
275}
276
277impl<'a> TryFrom<&'a str> for TableName<'a> {
278 type Error = Error;
279
280 fn try_from(name: &'a str) -> crate::Result<Self> {
281 Self::new(name)
282 }
283}
284
285impl AsRef<str> for TableName<'_> {
286 fn as_ref(&self) -> &str {
287 self.name
288 }
289}
290
291#[derive(Clone, Copy)]
298pub struct ColumnName<'a> {
299 name: &'a str,
300}
301
302impl<'a> ColumnName<'a> {
303 pub fn new(name: &'a str) -> crate::Result<Self> {
305 if name.is_empty() {
306 return Err(error::fmt!(
307 InvalidName,
308 "Column names must have a non-zero length."
309 ));
310 }
311
312 for (byte_idx, c) in name.char_indices() {
313 match c {
314 '?' | '.' | ',' | '\'' | '\"' | '\\' | '/' | ':' | ')' | '(' | '+' | '-' | '*'
315 | '%' | '~' | '\r' | '\n' | '\0' | '\u{0001}' | '\u{0002}' | '\u{0003}'
316 | '\u{0004}' | '\u{0005}' | '\u{0006}' | '\u{0007}' | '\u{0008}' | '\u{0009}'
317 | '\u{000b}' | '\u{000c}' | '\u{000e}' | '\u{000f}' | '\u{007f}' => {
318 return Err(error::fmt!(
319 InvalidName,
320 concat!(
321 "Bad string {:?}: ",
322 "Column names can't contain ",
323 "a {:?} character, which was found at ",
324 "byte position {}."
325 ),
326 name,
327 c,
328 byte_idx
329 ));
330 }
331 '\u{FEFF}' => {
332 return Err(error::fmt!(
335 InvalidName,
336 concat!(
337 "Bad string {:?}: ",
338 "Column names can't contain ",
339 "a UTF-8 BOM character, which was found at ",
340 "byte position {}."
341 ),
342 name,
343 byte_idx
344 ));
345 }
346 _ => (),
347 }
348 }
349
350 Ok(Self { name })
351 }
352
353 pub fn new_unchecked(name: &'a str) -> Self {
360 Self { name }
361 }
362}
363
364impl<'a> TryFrom<&'a str> for ColumnName<'a> {
365 type Error = Error;
366
367 fn try_from(name: &'a str) -> crate::Result<Self> {
368 Self::new(name)
369 }
370}
371
372impl AsRef<str> for ColumnName<'_> {
373 fn as_ref(&self) -> &str {
374 self.name
375 }
376}
377
378#[derive(Clone, Debug)]
379enum BufferInner {
380 Ilp(IlpBuffer),
381
382 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
383 Qwp(Box<QwpBuffer>),
384
385 #[cfg(feature = "_sender-qwp-ws")]
386 QwpWs(Box<QwpWsColumnarBuffer>),
387}
388
389#[derive(Clone, Debug)]
394pub struct Buffer {
395 inner: BufferInner,
396}
397
398const _: fn() = || {
402 fn assert_send_sync<T: Send + Sync>() {}
403 assert_send_sync::<Buffer>();
404};
405
406impl Buffer {
407 pub fn new(protocol_version: ProtocolVersion) -> Self {
409 Self {
410 inner: BufferInner::Ilp(IlpBuffer::new(protocol_version)),
411 }
412 }
413
414 pub fn with_max_name_len(protocol_version: ProtocolVersion, max_name_len: usize) -> Self {
416 Self {
417 inner: BufferInner::Ilp(IlpBuffer::with_max_name_len(protocol_version, max_name_len)),
418 }
419 }
420
421 pub fn with_init_capacity_and_max_name_len(
426 protocol_version: ProtocolVersion,
427 init_capacity: usize,
428 max_name_len: usize,
429 ) -> Self {
430 Self {
431 inner: BufferInner::Ilp(IlpBuffer::with_init_capacity_and_max_name_len(
432 protocol_version,
433 init_capacity,
434 max_name_len,
435 )),
436 }
437 }
438
439 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
440 pub fn new_qwp() -> Self {
441 Self::qwp_with_max_name_len(127)
442 }
443
444 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
445 pub fn qwp_with_max_name_len(max_name_len: usize) -> Self {
447 Self {
448 inner: BufferInner::Qwp(Box::new(QwpBuffer::new(max_name_len))),
449 }
450 }
451
452 #[cfg(feature = "_sender-qwp-ws")]
458 pub fn new_qwp_ws() -> Self {
459 Self::qwp_ws_with_max_name_len(127)
460 }
461
462 #[cfg(feature = "_sender-qwp-ws")]
464 pub fn qwp_ws_with_max_name_len(max_name_len: usize) -> Self {
465 Self {
466 inner: BufferInner::QwpWs(Box::new(QwpWsColumnarBuffer::new(max_name_len))),
467 }
468 }
469
470 #[cfg(feature = "_sync-sender")]
471 pub(crate) fn as_ilp(&self) -> Option<&IlpBuffer> {
472 match &self.inner {
473 BufferInner::Ilp(inner) => Some(inner),
474 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
475 BufferInner::Qwp(_) => None,
476 #[cfg(feature = "_sender-qwp-ws")]
477 BufferInner::QwpWs(_) => None,
478 }
479 }
480
481 #[cfg(any(
482 feature = "_sender-qwp-udp",
483 all(test, feature = "_sender-qwp-ws", feature = "_sender-http")
484 ))]
485 pub(crate) fn as_qwp(&self) -> Option<&QwpBuffer> {
486 match &self.inner {
487 BufferInner::Ilp(_) => None,
488 BufferInner::Qwp(inner) => Some(inner.as_ref()),
489 #[cfg(feature = "_sender-qwp-ws")]
490 BufferInner::QwpWs(_) => None,
491 }
492 }
493
494 #[cfg(feature = "_sender-qwp-ws")]
495 pub(crate) fn as_qwp_ws(&self) -> Option<&QwpWsColumnarBuffer> {
496 match &self.inner {
497 BufferInner::Ilp(_) => None,
498 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
499 BufferInner::Qwp(_) => None,
500 BufferInner::QwpWs(inner) => Some(inner.as_ref()),
501 }
502 }
503
504 pub fn protocol_version(&self) -> ProtocolVersion {
511 match &self.inner {
512 BufferInner::Ilp(inner) => inner.protocol_version(),
513 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
514 BufferInner::Qwp(_) => ProtocolVersion::V1,
515 #[cfg(feature = "_sender-qwp-ws")]
516 BufferInner::QwpWs(_) => ProtocolVersion::V1,
517 }
518 }
519
520 pub fn reserve(&mut self, additional: usize) {
528 match &mut self.inner {
529 BufferInner::Ilp(inner) => inner.reserve(additional),
530 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
531 BufferInner::Qwp(inner) => inner.reserve(additional),
532 #[cfg(feature = "_sender-qwp-ws")]
533 BufferInner::QwpWs(inner) => inner.reserve(additional),
534 }
535 }
536
537 pub fn len(&self) -> usize {
545 match &self.inner {
546 BufferInner::Ilp(inner) => inner.len(),
547 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
548 BufferInner::Qwp(inner) => inner.len(),
549 #[cfg(feature = "_sender-qwp-ws")]
550 BufferInner::QwpWs(inner) => inner.len(),
551 }
552 }
553
554 pub fn row_count(&self) -> usize {
559 match &self.inner {
560 BufferInner::Ilp(inner) => inner.row_count(),
561 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
562 BufferInner::Qwp(inner) => inner.row_count(),
563 #[cfg(feature = "_sender-qwp-ws")]
564 BufferInner::QwpWs(inner) => inner.row_count(),
565 }
566 }
567
568 pub fn transactional(&self) -> bool {
574 match &self.inner {
575 BufferInner::Ilp(inner) => inner.transactional(),
576 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
577 BufferInner::Qwp(_) => false,
578 #[cfg(feature = "_sender-qwp-ws")]
579 BufferInner::QwpWs(_) => false,
580 }
581 }
582
583 pub fn is_empty(&self) -> bool {
585 match &self.inner {
586 BufferInner::Ilp(inner) => inner.is_empty(),
587 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
588 BufferInner::Qwp(inner) => inner.is_empty(),
589 #[cfg(feature = "_sender-qwp-ws")]
590 BufferInner::QwpWs(inner) => inner.is_empty(),
591 }
592 }
593
594 pub fn capacity(&self) -> usize {
600 match &self.inner {
601 BufferInner::Ilp(inner) => inner.capacity(),
602 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
603 BufferInner::Qwp(inner) => inner.capacity(),
604 #[cfg(feature = "_sender-qwp-ws")]
605 BufferInner::QwpWs(inner) => inner.capacity(),
606 }
607 }
608
609 pub fn as_bytes(&self) -> &[u8] {
614 match &self.inner {
615 BufferInner::Ilp(inner) => inner.as_bytes(),
616 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
617 BufferInner::Qwp(inner) => inner.as_bytes(),
618 #[cfg(feature = "_sender-qwp-ws")]
619 BufferInner::QwpWs(inner) => inner.as_bytes(),
620 }
621 }
622
623 pub fn set_marker(&mut self) -> crate::Result<()> {
629 match &mut self.inner {
630 BufferInner::Ilp(inner) => inner.set_marker(),
631 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
632 BufferInner::Qwp(inner) => inner.set_marker(),
633 #[cfg(feature = "_sender-qwp-ws")]
634 BufferInner::QwpWs(inner) => inner.set_marker(),
635 }
636 }
637
638 pub fn bookmark(&mut self) -> crate::Result<Bookmark> {
643 match &mut self.inner {
644 BufferInner::Ilp(inner) => inner.bookmark(),
645 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
646 BufferInner::Qwp(inner) => inner.bookmark(),
647 #[cfg(feature = "_sender-qwp-ws")]
648 BufferInner::QwpWs(inner) => inner.bookmark(),
649 }
650 }
651
652 pub fn rewind_to_bookmark(&mut self, bookmark: Bookmark) -> crate::Result<()> {
655 match &mut self.inner {
656 BufferInner::Ilp(inner) => inner.rewind_to_bookmark(bookmark),
657 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
658 BufferInner::Qwp(inner) => inner.rewind_to_bookmark(bookmark),
659 #[cfg(feature = "_sender-qwp-ws")]
660 BufferInner::QwpWs(inner) => inner.rewind_to_bookmark(bookmark),
661 }
662 }
663
664 pub fn clear_bookmark(&mut self, bookmark: Bookmark) {
666 match &mut self.inner {
667 BufferInner::Ilp(inner) => inner.clear_bookmark(bookmark),
668 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
669 BufferInner::Qwp(inner) => inner.clear_bookmark(bookmark),
670 #[cfg(feature = "_sender-qwp-ws")]
671 BufferInner::QwpWs(inner) => inner.clear_bookmark(bookmark),
672 }
673 }
674
675 pub fn rewind_to_marker(&mut self) -> crate::Result<()> {
683 match &mut self.inner {
684 BufferInner::Ilp(inner) => inner.rewind_to_marker(),
685 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
686 BufferInner::Qwp(inner) => inner.rewind_to_marker(),
687 #[cfg(feature = "_sender-qwp-ws")]
688 BufferInner::QwpWs(inner) => inner.rewind_to_marker(),
689 }
690 }
691
692 pub fn clear_marker(&mut self) {
695 match &mut self.inner {
696 BufferInner::Ilp(inner) => inner.clear_marker(),
697 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
698 BufferInner::Qwp(inner) => inner.clear_marker(),
699 #[cfg(feature = "_sender-qwp-ws")]
700 BufferInner::QwpWs(inner) => inner.clear_marker(),
701 }
702 }
703
704 pub fn clear(&mut self) {
706 match &mut self.inner {
707 BufferInner::Ilp(inner) => inner.clear(),
708 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
709 BufferInner::Qwp(inner) => inner.clear(),
710 #[cfg(feature = "_sender-qwp-ws")]
711 BufferInner::QwpWs(inner) => inner.clear(),
712 }
713 }
714
715 pub fn check_can_flush(&self) -> crate::Result<()> {
721 match &self.inner {
722 BufferInner::Ilp(inner) => inner.check_can_flush(),
723 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
724 BufferInner::Qwp(inner) => inner.check_can_flush(),
725 #[cfg(feature = "_sender-qwp-ws")]
726 BufferInner::QwpWs(inner) => inner.check_can_flush(),
727 }
728 }
729
730 #[inline(always)]
735 pub fn table<'a, N>(&mut self, name: N) -> crate::Result<&mut Self>
736 where
737 N: AsRef<str> + TryInto<TableName<'a>>,
738 Error: From<N::Error>,
739 {
740 match &mut self.inner {
741 BufferInner::Ilp(inner) => {
742 inner.table(name)?;
743 }
744 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
745 BufferInner::Qwp(inner) => {
746 inner.table(name)?;
747 }
748 #[cfg(feature = "_sender-qwp-ws")]
749 BufferInner::QwpWs(inner) => {
750 inner.table(name)?;
751 }
752 }
753 Ok(self)
754 }
755
756 #[inline(always)]
773 pub fn symbol<'a, N, S>(&mut self, name: N, value: S) -> crate::Result<&mut Self>
774 where
775 N: AsRef<str> + TryInto<ColumnName<'a>>,
776 S: AsRef<str>,
777 Error: From<N::Error>,
778 {
779 match &mut self.inner {
780 BufferInner::Ilp(inner) => {
781 inner.symbol(name, value)?;
782 }
783 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
784 BufferInner::Qwp(inner) => {
785 inner.symbol(name, value)?;
786 }
787 #[cfg(feature = "_sender-qwp-ws")]
788 BufferInner::QwpWs(inner) => {
789 inner.symbol(name, value)?;
790 }
791 }
792 Ok(self)
793 }
794
795 pub fn symbol_opt<'a, N, S>(&mut self, name: N, value: Option<S>) -> crate::Result<&mut Self>
800 where
801 N: AsRef<str> + TryInto<ColumnName<'a>>,
802 S: AsRef<str>,
803 Error: From<N::Error>,
804 {
805 if let Some(value) = value {
806 self.symbol(name, value)
807 } else {
808 Ok(self)
809 }
810 }
811
812 pub fn column_bool<'a, N>(&mut self, name: N, value: bool) -> crate::Result<&mut Self>
814 where
815 N: AsRef<str> + TryInto<ColumnName<'a>>,
816 Error: From<N::Error>,
817 {
818 match &mut self.inner {
819 BufferInner::Ilp(inner) => {
820 inner.column_bool(name, value)?;
821 }
822 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
823 BufferInner::Qwp(inner) => {
824 inner.column_bool(name, value)?;
825 }
826 #[cfg(feature = "_sender-qwp-ws")]
827 BufferInner::QwpWs(inner) => {
828 inner.column_bool(name, value)?;
829 }
830 }
831 Ok(self)
832 }
833
834 pub fn column_bool_opt<'a, N>(
836 &mut self,
837 name: N,
838 value: Option<bool>,
839 ) -> crate::Result<&mut Self>
840 where
841 N: AsRef<str> + TryInto<ColumnName<'a>>,
842 Error: From<N::Error>,
843 {
844 if let Some(value) = value {
845 self.column_bool(name, value)
846 } else {
847 Ok(self)
848 }
849 }
850
851 #[inline(always)]
853 pub fn column_i64<'a, N>(&mut self, name: N, value: i64) -> crate::Result<&mut Self>
854 where
855 N: AsRef<str> + TryInto<ColumnName<'a>>,
856 Error: From<N::Error>,
857 {
858 match &mut self.inner {
859 BufferInner::Ilp(inner) => {
860 inner.column_i64(name, value)?;
861 }
862 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
863 BufferInner::Qwp(inner) => {
864 inner.column_i64(name, value)?;
865 }
866 #[cfg(feature = "_sender-qwp-ws")]
867 BufferInner::QwpWs(inner) => {
868 inner.column_i64(name, value)?;
869 }
870 }
871 Ok(self)
872 }
873
874 pub fn column_i64_opt<'a, N>(&mut self, name: N, value: Option<i64>) -> crate::Result<&mut Self>
876 where
877 N: AsRef<str> + TryInto<ColumnName<'a>>,
878 Error: From<N::Error>,
879 {
880 if let Some(value) = value {
881 self.column_i64(name, value)
882 } else {
883 Ok(self)
884 }
885 }
886
887 pub fn column_i8<'a, N>(&mut self, name: N, value: i8) -> crate::Result<&mut Self>
889 where
890 N: AsRef<str> + TryInto<ColumnName<'a>>,
891 Error: From<N::Error>,
892 {
893 let _ = (&name, &value);
894 match &mut self.inner {
895 BufferInner::Ilp(_) => Err(error::fmt!(
896 InvalidApiCall,
897 "column_i8 requires a QWP transport (ws:: or udp::)"
898 )),
899 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
900 BufferInner::Qwp(inner) => {
901 inner.column_i8(name, value)?;
902 Ok(self)
903 }
904 #[cfg(feature = "_sender-qwp-ws")]
905 BufferInner::QwpWs(inner) => {
906 inner.column_i8(name, value)?;
907 Ok(self)
908 }
909 }
910 }
911
912 pub fn column_i8_opt<'a, N>(&mut self, name: N, value: Option<i8>) -> crate::Result<&mut Self>
914 where
915 N: AsRef<str> + TryInto<ColumnName<'a>>,
916 Error: From<N::Error>,
917 {
918 if let Some(value) = value {
919 self.column_i8(name, value)
920 } else {
921 Ok(self)
922 }
923 }
924
925 pub fn column_i16<'a, N>(&mut self, name: N, value: i16) -> crate::Result<&mut Self>
927 where
928 N: AsRef<str> + TryInto<ColumnName<'a>>,
929 Error: From<N::Error>,
930 {
931 let _ = (&name, &value);
932 match &mut self.inner {
933 BufferInner::Ilp(_) => Err(error::fmt!(
934 InvalidApiCall,
935 "column_i16 requires a QWP transport (ws:: or udp::)"
936 )),
937 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
938 BufferInner::Qwp(inner) => {
939 inner.column_i16(name, value)?;
940 Ok(self)
941 }
942 #[cfg(feature = "_sender-qwp-ws")]
943 BufferInner::QwpWs(inner) => {
944 inner.column_i16(name, value)?;
945 Ok(self)
946 }
947 }
948 }
949
950 pub fn column_i16_opt<'a, N>(&mut self, name: N, value: Option<i16>) -> crate::Result<&mut Self>
952 where
953 N: AsRef<str> + TryInto<ColumnName<'a>>,
954 Error: From<N::Error>,
955 {
956 if let Some(value) = value {
957 self.column_i16(name, value)
958 } else {
959 Ok(self)
960 }
961 }
962
963 pub fn column_i32<'a, N>(&mut self, name: N, value: i32) -> crate::Result<&mut Self>
965 where
966 N: AsRef<str> + TryInto<ColumnName<'a>>,
967 Error: From<N::Error>,
968 {
969 let _ = (&name, &value);
970 match &mut self.inner {
971 BufferInner::Ilp(_) => Err(error::fmt!(
972 InvalidApiCall,
973 "column_i32 requires a QWP transport (ws:: or udp::)"
974 )),
975 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
976 BufferInner::Qwp(inner) => {
977 inner.column_i32(name, value)?;
978 Ok(self)
979 }
980 #[cfg(feature = "_sender-qwp-ws")]
981 BufferInner::QwpWs(inner) => {
982 inner.column_i32(name, value)?;
983 Ok(self)
984 }
985 }
986 }
987
988 pub fn column_i32_opt<'a, N>(&mut self, name: N, value: Option<i32>) -> crate::Result<&mut Self>
990 where
991 N: AsRef<str> + TryInto<ColumnName<'a>>,
992 Error: From<N::Error>,
993 {
994 if let Some(value) = value {
995 self.column_i32(name, value)
996 } else {
997 Ok(self)
998 }
999 }
1000
1001 pub fn column_f32<'a, N>(&mut self, name: N, value: f32) -> crate::Result<&mut Self>
1003 where
1004 N: AsRef<str> + TryInto<ColumnName<'a>>,
1005 Error: From<N::Error>,
1006 {
1007 let _ = (&name, &value);
1008 match &mut self.inner {
1009 BufferInner::Ilp(_) => Err(error::fmt!(
1010 InvalidApiCall,
1011 "column_f32 requires a QWP transport (ws:: or udp::)"
1012 )),
1013 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1014 BufferInner::Qwp(inner) => {
1015 inner.column_f32(name, value)?;
1016 Ok(self)
1017 }
1018 #[cfg(feature = "_sender-qwp-ws")]
1019 BufferInner::QwpWs(inner) => {
1020 inner.column_f32(name, value)?;
1021 Ok(self)
1022 }
1023 }
1024 }
1025
1026 pub fn column_f32_opt<'a, N>(&mut self, name: N, value: Option<f32>) -> crate::Result<&mut Self>
1028 where
1029 N: AsRef<str> + TryInto<ColumnName<'a>>,
1030 Error: From<N::Error>,
1031 {
1032 if let Some(value) = value {
1033 self.column_f32(name, value)
1034 } else {
1035 Ok(self)
1036 }
1037 }
1038
1039 #[inline(always)]
1041 pub fn column_f64<'a, N>(&mut self, name: N, value: f64) -> crate::Result<&mut Self>
1042 where
1043 N: AsRef<str> + TryInto<ColumnName<'a>>,
1044 Error: From<N::Error>,
1045 {
1046 match &mut self.inner {
1047 BufferInner::Ilp(inner) => {
1048 inner.column_f64(name, value)?;
1049 }
1050 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1051 BufferInner::Qwp(inner) => {
1052 inner.column_f64(name, value)?;
1053 }
1054 #[cfg(feature = "_sender-qwp-ws")]
1055 BufferInner::QwpWs(inner) => {
1056 inner.column_f64(name, value)?;
1057 }
1058 }
1059 Ok(self)
1060 }
1061
1062 pub fn column_f64_opt<'a, N>(&mut self, name: N, value: Option<f64>) -> crate::Result<&mut Self>
1064 where
1065 N: AsRef<str> + TryInto<ColumnName<'a>>,
1066 Error: From<N::Error>,
1067 {
1068 if let Some(value) = value {
1069 self.column_f64(name, value)
1070 } else {
1071 Ok(self)
1072 }
1073 }
1074
1075 #[inline(always)]
1077 pub fn column_str<'a, N, S>(&mut self, name: N, value: S) -> crate::Result<&mut Self>
1078 where
1079 N: AsRef<str> + TryInto<ColumnName<'a>>,
1080 S: AsRef<str>,
1081 Error: From<N::Error>,
1082 {
1083 match &mut self.inner {
1084 BufferInner::Ilp(inner) => {
1085 inner.column_str(name, value)?;
1086 }
1087 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1088 BufferInner::Qwp(inner) => {
1089 inner.column_str(name, value)?;
1090 }
1091 #[cfg(feature = "_sender-qwp-ws")]
1092 BufferInner::QwpWs(inner) => {
1093 inner.column_str(name, value)?;
1094 }
1095 }
1096 Ok(self)
1097 }
1098
1099 pub fn column_str_opt<'a, N, S>(
1101 &mut self,
1102 name: N,
1103 value: Option<S>,
1104 ) -> crate::Result<&mut Self>
1105 where
1106 N: AsRef<str> + TryInto<ColumnName<'a>>,
1107 S: AsRef<str>,
1108 Error: From<N::Error>,
1109 {
1110 if let Some(value) = value {
1111 self.column_str(name, value)
1112 } else {
1113 Ok(self)
1114 }
1115 }
1116
1117 pub fn column_dec<'a, N, S>(&mut self, name: N, value: S) -> crate::Result<&mut Self>
1123 where
1124 N: AsRef<str> + TryInto<ColumnName<'a>>,
1125 S: TryInto<DecimalView<'a>>,
1126 Error: From<N::Error>,
1127 Error: From<S::Error>,
1128 {
1129 match &mut self.inner {
1130 BufferInner::Ilp(inner) => {
1131 inner.column_dec(name, value)?;
1132 }
1133 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1134 BufferInner::Qwp(inner) => {
1135 inner.column_dec(name, value)?;
1136 }
1137 #[cfg(feature = "_sender-qwp-ws")]
1138 BufferInner::QwpWs(inner) => {
1139 inner.column_dec(name, value)?;
1140 }
1141 }
1142 Ok(self)
1143 }
1144
1145 pub fn column_dec_opt<'a, N, S>(
1147 &mut self,
1148 name: N,
1149 value: Option<S>,
1150 ) -> crate::Result<&mut Self>
1151 where
1152 N: AsRef<str> + TryInto<ColumnName<'a>>,
1153 S: TryInto<DecimalView<'a>>,
1154 Error: From<N::Error>,
1155 Error: From<S::Error>,
1156 {
1157 if let Some(value) = value {
1158 self.column_dec(name, value)
1159 } else {
1160 Ok(self)
1161 }
1162 }
1163
1164 pub fn column_dec64<'a, N, S>(&mut self, name: N, value: S) -> crate::Result<&mut Self>
1169 where
1170 N: AsRef<str> + TryInto<ColumnName<'a>>,
1171 S: TryInto<DecimalView<'a>>,
1172 Error: From<N::Error>,
1173 Error: From<S::Error>,
1174 {
1175 let _ = &name;
1176 match &mut self.inner {
1177 BufferInner::Ilp(_) => {
1178 let _ = value.try_into().map_err(Error::from)?;
1179 Err(error::fmt!(
1180 InvalidApiCall,
1181 "column_dec64 requires a QWP transport (ws:: or udp::)"
1182 ))
1183 }
1184 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1185 BufferInner::Qwp(inner) => {
1186 inner.column_dec64(name, value)?;
1187 Ok(self)
1188 }
1189 #[cfg(feature = "_sender-qwp-ws")]
1190 BufferInner::QwpWs(inner) => {
1191 inner.column_dec64(name, value)?;
1192 Ok(self)
1193 }
1194 }
1195 }
1196
1197 pub fn column_dec64_opt<'a, N, S>(
1199 &mut self,
1200 name: N,
1201 value: Option<S>,
1202 ) -> crate::Result<&mut Self>
1203 where
1204 N: AsRef<str> + TryInto<ColumnName<'a>>,
1205 S: TryInto<DecimalView<'a>>,
1206 Error: From<N::Error>,
1207 Error: From<S::Error>,
1208 {
1209 if let Some(value) = value {
1210 self.column_dec64(name, value)
1211 } else {
1212 Ok(self)
1213 }
1214 }
1215
1216 pub fn column_dec128<'a, N, S>(&mut self, name: N, value: S) -> crate::Result<&mut Self>
1221 where
1222 N: AsRef<str> + TryInto<ColumnName<'a>>,
1223 S: TryInto<DecimalView<'a>>,
1224 Error: From<N::Error>,
1225 Error: From<S::Error>,
1226 {
1227 let _ = &name;
1228 match &mut self.inner {
1229 BufferInner::Ilp(_) => {
1230 let _ = value.try_into().map_err(Error::from)?;
1231 Err(error::fmt!(
1232 InvalidApiCall,
1233 "column_dec128 requires a QWP transport (ws:: or udp::)"
1234 ))
1235 }
1236 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1237 BufferInner::Qwp(inner) => {
1238 inner.column_dec128(name, value)?;
1239 Ok(self)
1240 }
1241 #[cfg(feature = "_sender-qwp-ws")]
1242 BufferInner::QwpWs(inner) => {
1243 inner.column_dec128(name, value)?;
1244 Ok(self)
1245 }
1246 }
1247 }
1248
1249 pub fn column_dec128_opt<'a, N, S>(
1251 &mut self,
1252 name: N,
1253 value: Option<S>,
1254 ) -> crate::Result<&mut Self>
1255 where
1256 N: AsRef<str> + TryInto<ColumnName<'a>>,
1257 S: TryInto<DecimalView<'a>>,
1258 Error: From<N::Error>,
1259 Error: From<S::Error>,
1260 {
1261 if let Some(value) = value {
1262 self.column_dec128(name, value)
1263 } else {
1264 Ok(self)
1265 }
1266 }
1267
1268 pub fn column_uuid<'a, N>(&mut self, name: N, lo: u64, hi: u64) -> crate::Result<&mut Self>
1273 where
1274 N: AsRef<str> + TryInto<ColumnName<'a>>,
1275 Error: From<N::Error>,
1276 {
1277 let _ = &name;
1278 let _ = (lo, hi);
1279 match &mut self.inner {
1280 BufferInner::Ilp(_) => Err(error::fmt!(
1281 InvalidApiCall,
1282 "column_uuid requires a QWP transport (ws:: or udp::)"
1283 )),
1284 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1285 BufferInner::Qwp(inner) => {
1286 inner.column_uuid(name, lo, hi)?;
1287 Ok(self)
1288 }
1289 #[cfg(feature = "_sender-qwp-ws")]
1290 BufferInner::QwpWs(inner) => {
1291 inner.column_uuid(name, lo, hi)?;
1292 Ok(self)
1293 }
1294 }
1295 }
1296
1297 pub fn column_uuid_opt<'a, N>(
1299 &mut self,
1300 name: N,
1301 value: Option<(u64, u64)>,
1302 ) -> crate::Result<&mut Self>
1303 where
1304 N: AsRef<str> + TryInto<ColumnName<'a>>,
1305 Error: From<N::Error>,
1306 {
1307 if let Some((lo, hi)) = value {
1308 self.column_uuid(name, lo, hi)
1309 } else {
1310 Ok(self)
1311 }
1312 }
1313
1314 pub fn column_long256<'a, N>(&mut self, name: N, value: &[u8; 32]) -> crate::Result<&mut Self>
1319 where
1320 N: AsRef<str> + TryInto<ColumnName<'a>>,
1321 Error: From<N::Error>,
1322 {
1323 let _ = (&name, value);
1324 match &mut self.inner {
1325 BufferInner::Ilp(_) => Err(error::fmt!(
1326 InvalidApiCall,
1327 "column_long256 requires a QWP transport (ws:: or udp::)"
1328 )),
1329 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1330 BufferInner::Qwp(inner) => {
1331 inner.column_long256(name, value)?;
1332 Ok(self)
1333 }
1334 #[cfg(feature = "_sender-qwp-ws")]
1335 BufferInner::QwpWs(inner) => {
1336 inner.column_long256(name, value)?;
1337 Ok(self)
1338 }
1339 }
1340 }
1341
1342 pub fn column_long256_opt<'a, N>(
1344 &mut self,
1345 name: N,
1346 value: Option<&[u8; 32]>,
1347 ) -> crate::Result<&mut Self>
1348 where
1349 N: AsRef<str> + TryInto<ColumnName<'a>>,
1350 Error: From<N::Error>,
1351 {
1352 if let Some(value) = value {
1353 self.column_long256(name, value)
1354 } else {
1355 Ok(self)
1356 }
1357 }
1358
1359 pub fn column_ipv4<'a, N>(
1366 &mut self,
1367 name: N,
1368 value: std::net::Ipv4Addr,
1369 ) -> crate::Result<&mut Self>
1370 where
1371 N: AsRef<str> + TryInto<ColumnName<'a>>,
1372 Error: From<N::Error>,
1373 {
1374 let _ = (&name, value);
1375 let packed = u32::from(value);
1376 let _ = packed;
1377 match &mut self.inner {
1378 BufferInner::Ilp(_) => Err(error::fmt!(
1379 InvalidApiCall,
1380 "column_ipv4 requires a QWP transport (ws:: or udp::)"
1381 )),
1382 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1383 BufferInner::Qwp(inner) => {
1384 inner.column_ipv4(name, packed)?;
1385 Ok(self)
1386 }
1387 #[cfg(feature = "_sender-qwp-ws")]
1388 BufferInner::QwpWs(inner) => {
1389 inner.column_ipv4(name, packed)?;
1390 Ok(self)
1391 }
1392 }
1393 }
1394
1395 pub fn column_ipv4_opt<'a, N>(
1397 &mut self,
1398 name: N,
1399 value: Option<std::net::Ipv4Addr>,
1400 ) -> crate::Result<&mut Self>
1401 where
1402 N: AsRef<str> + TryInto<ColumnName<'a>>,
1403 Error: From<N::Error>,
1404 {
1405 if let Some(value) = value {
1406 self.column_ipv4(name, value)
1407 } else {
1408 Ok(self)
1409 }
1410 }
1411
1412 pub fn column_date<'a, N>(&mut self, name: N, millis: i64) -> crate::Result<&mut Self>
1414 where
1415 N: AsRef<str> + TryInto<ColumnName<'a>>,
1416 Error: From<N::Error>,
1417 {
1418 let _ = (&name, &millis);
1419 match &mut self.inner {
1420 BufferInner::Ilp(_) => Err(error::fmt!(
1421 InvalidApiCall,
1422 "column_date requires a QWP transport (ws:: or udp::)"
1423 )),
1424 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1425 BufferInner::Qwp(inner) => {
1426 inner.column_date(name, millis)?;
1427 Ok(self)
1428 }
1429 #[cfg(feature = "_sender-qwp-ws")]
1430 BufferInner::QwpWs(inner) => {
1431 inner.column_date(name, millis)?;
1432 Ok(self)
1433 }
1434 }
1435 }
1436
1437 pub fn column_date_opt<'a, N>(
1439 &mut self,
1440 name: N,
1441 value: Option<i64>,
1442 ) -> crate::Result<&mut Self>
1443 where
1444 N: AsRef<str> + TryInto<ColumnName<'a>>,
1445 Error: From<N::Error>,
1446 {
1447 if let Some(value) = value {
1448 self.column_date(name, value)
1449 } else {
1450 Ok(self)
1451 }
1452 }
1453
1454 pub fn column_char<'a, N>(&mut self, name: N, value: u16) -> crate::Result<&mut Self>
1456 where
1457 N: AsRef<str> + TryInto<ColumnName<'a>>,
1458 Error: From<N::Error>,
1459 {
1460 let _ = (&name, &value);
1461 match &mut self.inner {
1462 BufferInner::Ilp(_) => Err(error::fmt!(
1463 InvalidApiCall,
1464 "column_char requires a QWP transport (ws:: or udp::)"
1465 )),
1466 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1467 BufferInner::Qwp(inner) => {
1468 inner.column_char(name, value)?;
1469 Ok(self)
1470 }
1471 #[cfg(feature = "_sender-qwp-ws")]
1472 BufferInner::QwpWs(inner) => {
1473 inner.column_char(name, value)?;
1474 Ok(self)
1475 }
1476 }
1477 }
1478
1479 pub fn column_char_opt<'a, N>(
1481 &mut self,
1482 name: N,
1483 value: Option<u16>,
1484 ) -> crate::Result<&mut Self>
1485 where
1486 N: AsRef<str> + TryInto<ColumnName<'a>>,
1487 Error: From<N::Error>,
1488 {
1489 if let Some(value) = value {
1490 self.column_char(name, value)
1491 } else {
1492 Ok(self)
1493 }
1494 }
1495
1496 pub fn column_binary<'a, N>(&mut self, name: N, value: &[u8]) -> crate::Result<&mut Self>
1500 where
1501 N: AsRef<str> + TryInto<ColumnName<'a>>,
1502 Error: From<N::Error>,
1503 {
1504 let _ = (&name, value);
1505 match &mut self.inner {
1506 BufferInner::Ilp(_) => Err(error::fmt!(
1507 InvalidApiCall,
1508 "column_binary requires a QWP transport (ws:: or udp::)"
1509 )),
1510 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1511 BufferInner::Qwp(inner) => {
1512 inner.column_binary(name, value)?;
1513 Ok(self)
1514 }
1515 #[cfg(feature = "_sender-qwp-ws")]
1516 BufferInner::QwpWs(inner) => {
1517 inner.column_binary(name, value)?;
1518 Ok(self)
1519 }
1520 }
1521 }
1522
1523 pub fn column_binary_opt<'a, N>(
1525 &mut self,
1526 name: N,
1527 value: Option<&[u8]>,
1528 ) -> crate::Result<&mut Self>
1529 where
1530 N: AsRef<str> + TryInto<ColumnName<'a>>,
1531 Error: From<N::Error>,
1532 {
1533 if let Some(value) = value {
1534 self.column_binary(name, value)
1535 } else {
1536 Ok(self)
1537 }
1538 }
1539
1540 pub fn column_geohash<'a, N>(
1543 &mut self,
1544 name: N,
1545 bits: u64,
1546 precision_bits: u8,
1547 ) -> crate::Result<&mut Self>
1548 where
1549 N: AsRef<str> + TryInto<ColumnName<'a>>,
1550 Error: From<N::Error>,
1551 {
1552 let _ = (&name, &bits, &precision_bits);
1553 match &mut self.inner {
1554 BufferInner::Ilp(_) => Err(error::fmt!(
1555 InvalidApiCall,
1556 "column_geohash requires a QWP transport (ws:: or udp::)"
1557 )),
1558 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1559 BufferInner::Qwp(inner) => {
1560 inner.column_geohash(name, bits, precision_bits)?;
1561 Ok(self)
1562 }
1563 #[cfg(feature = "_sender-qwp-ws")]
1564 BufferInner::QwpWs(inner) => {
1565 inner.column_geohash(name, bits, precision_bits)?;
1566 Ok(self)
1567 }
1568 }
1569 }
1570
1571 pub fn column_geohash_opt<'a, N>(
1573 &mut self,
1574 name: N,
1575 value: Option<(u64, u8)>,
1576 ) -> crate::Result<&mut Self>
1577 where
1578 N: AsRef<str> + TryInto<ColumnName<'a>>,
1579 Error: From<N::Error>,
1580 {
1581 if let Some((bits, precision)) = value {
1582 self.column_geohash(name, bits, precision)
1583 } else {
1584 Ok(self)
1585 }
1586 }
1587
1588 #[allow(private_bounds)]
1589 pub fn column_arr<'a, N, T, D>(&mut self, name: N, view: &T) -> crate::Result<&mut Self>
1597 where
1598 N: AsRef<str> + TryInto<ColumnName<'a>>,
1599 T: NdArrayView<D>,
1600 D: ArrayElement + ArrayElementSealed,
1601 Error: From<N::Error>,
1602 {
1603 match &mut self.inner {
1604 BufferInner::Ilp(inner) => {
1605 if D::type_tag() != 10 {
1606 return Err(error::fmt!(
1607 InvalidApiCall,
1608 "column_arr with non-f64 element type requires a QWP transport (ws:: or udp::)"
1609 ));
1610 }
1611 inner.column_arr(name, view)?;
1612 }
1613 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1614 BufferInner::Qwp(inner) => {
1615 inner.column_arr(name, view)?;
1616 }
1617 #[cfg(feature = "_sender-qwp-ws")]
1618 BufferInner::QwpWs(inner) => {
1619 inner.column_arr(name, view)?;
1620 }
1621 }
1622 Ok(self)
1623 }
1624
1625 #[allow(private_bounds)]
1627 pub fn column_arr_opt<'a, N, T, D>(
1628 &mut self,
1629 name: N,
1630 value: Option<&T>,
1631 ) -> crate::Result<&mut Self>
1632 where
1633 N: AsRef<str> + TryInto<ColumnName<'a>>,
1634 T: NdArrayView<D>,
1635 D: ArrayElement + ArrayElementSealed,
1636 Error: From<N::Error>,
1637 {
1638 if let Some(value) = value {
1639 self.column_arr(name, value)
1640 } else {
1641 Ok(self)
1642 }
1643 }
1644
1645 #[inline(always)]
1649 pub fn column_ts<'a, N, T>(&mut self, name: N, value: T) -> crate::Result<&mut Self>
1650 where
1651 N: AsRef<str> + TryInto<ColumnName<'a>>,
1652 T: TryInto<Timestamp>,
1653 Error: From<N::Error>,
1654 Error: From<T::Error>,
1655 {
1656 match &mut self.inner {
1657 BufferInner::Ilp(inner) => {
1658 inner.column_ts(name, value)?;
1659 }
1660 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1661 BufferInner::Qwp(inner) => {
1662 inner.column_ts(name, value)?;
1663 }
1664 #[cfg(feature = "_sender-qwp-ws")]
1665 BufferInner::QwpWs(inner) => {
1666 inner.column_ts(name, value)?;
1667 }
1668 }
1669 Ok(self)
1670 }
1671
1672 pub fn column_ts_opt<'a, N, T>(&mut self, name: N, value: Option<T>) -> crate::Result<&mut Self>
1674 where
1675 N: AsRef<str> + TryInto<ColumnName<'a>>,
1676 T: TryInto<Timestamp>,
1677 Error: From<N::Error>,
1678 Error: From<T::Error>,
1679 {
1680 if let Some(value) = value {
1681 self.column_ts(name, value)
1682 } else {
1683 Ok(self)
1684 }
1685 }
1686
1687 #[inline(always)]
1692 pub fn at<T>(&mut self, timestamp: T) -> crate::Result<()>
1693 where
1694 T: TryInto<Timestamp>,
1695 Error: From<T::Error>,
1696 {
1697 match &mut self.inner {
1698 BufferInner::Ilp(inner) => inner.at(timestamp),
1699 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1700 BufferInner::Qwp(inner) => inner.at(timestamp),
1701 #[cfg(feature = "_sender-qwp-ws")]
1702 BufferInner::QwpWs(inner) => inner.at(timestamp),
1703 }
1704 }
1705
1706 #[inline(always)]
1712 pub fn at_now(&mut self) -> crate::Result<()> {
1713 match &mut self.inner {
1714 BufferInner::Ilp(inner) => inner.at_now(),
1715 #[cfg(any(feature = "_sender-qwp-udp", feature = "_sender-qwp-ws"))]
1716 BufferInner::Qwp(inner) => inner.at_now(),
1717 #[cfg(feature = "_sender-qwp-ws")]
1718 BufferInner::QwpWs(inner) => inner.at_now(),
1719 }
1720 }
1721}
1722
1723#[cfg(test)]
1724mod tests {
1725 use super::{Bookmark, Buffer, ColumnName, StoredBookmark, TableName};
1726 use crate::ErrorCode;
1727 use crate::ingress::ProtocolVersion;
1728
1729 #[test]
1730 fn stored_bookmark_reports_missing_bookmark_when_never_captured() {
1731 let bookmark = Bookmark::from_raw(7, 1);
1732 let stored = StoredBookmark::<u8>::new();
1733 let err = stored.restore(7, bookmark).unwrap_err();
1734 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1735 assert_eq!(err.msg(), "Can't rewind to the bookmark: No bookmark set.");
1736 }
1737
1738 #[test]
1739 fn stored_bookmark_ignores_invalid_zero_origin_clear() {
1740 let mut stored = StoredBookmark::<u8>::new();
1741 let bookmark = stored.capture(7, 42);
1742
1743 stored.clear_if_matches(7, Bookmark::from_raw(0, 0));
1744
1745 assert_eq!(stored.restore(7, bookmark).unwrap(), 42);
1746 }
1747
1748 #[test]
1749 fn buffer_column_i8_rejects_ilp_buffer() {
1750 let mut buf = Buffer::new(ProtocolVersion::V2);
1751 buf.table("trades").unwrap();
1752 let err = buf.column_i8("v", 1).unwrap_err();
1753 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1754 assert!(
1755 err.msg().contains("column_i8"),
1756 "error message should name column_i8: {}",
1757 err.msg()
1758 );
1759 }
1760
1761 #[test]
1762 fn buffer_column_i16_rejects_ilp_buffer() {
1763 let mut buf = Buffer::new(ProtocolVersion::V2);
1764 buf.table("trades").unwrap();
1765 let err = buf.column_i16("v", 1).unwrap_err();
1766 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1767 assert!(err.msg().contains("column_i16"), "{}", err.msg());
1768 }
1769
1770 #[test]
1771 fn buffer_column_i32_rejects_ilp_buffer() {
1772 let mut buf = Buffer::new(ProtocolVersion::V2);
1773 buf.table("trades").unwrap();
1774 let err = buf.column_i32("v", 1).unwrap_err();
1775 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1776 assert!(err.msg().contains("column_i32"), "{}", err.msg());
1777 }
1778
1779 #[test]
1780 fn buffer_column_dec64_rejects_ilp_buffer() {
1781 let mut buf = Buffer::new(ProtocolVersion::V3);
1782 buf.table("trades").unwrap();
1783 let err = buf.column_dec64("v", "1.25").unwrap_err();
1784 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1785 assert!(err.msg().contains("column_dec64"), "{}", err.msg());
1786 }
1787
1788 #[test]
1789 fn buffer_column_dec128_rejects_ilp_buffer() {
1790 let mut buf = Buffer::new(ProtocolVersion::V3);
1791 buf.table("trades").unwrap();
1792 let err = buf.column_dec128("v", "1.25").unwrap_err();
1793 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1794 assert!(err.msg().contains("column_dec128"), "{}", err.msg());
1795 }
1796
1797 #[test]
1798 fn buffer_column_uuid_rejects_ilp_buffer() {
1799 let mut buf = Buffer::new(ProtocolVersion::V2);
1800 buf.table("trades").unwrap();
1801 let err = buf.column_uuid("v", 1, 2).unwrap_err();
1802 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1803 assert!(err.msg().contains("column_uuid"), "{}", err.msg());
1804 }
1805
1806 #[test]
1807 fn buffer_column_long256_rejects_ilp_buffer() {
1808 let mut buf = Buffer::new(ProtocolVersion::V2);
1809 buf.table("trades").unwrap();
1810 let err = buf.column_long256("v", &[0u8; 32]).unwrap_err();
1811 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1812 assert!(err.msg().contains("column_long256"), "{}", err.msg());
1813 }
1814
1815 #[test]
1816 fn buffer_column_ipv4_rejects_ilp_buffer() {
1817 let mut buf = Buffer::new(ProtocolVersion::V2);
1818 buf.table("trades").unwrap();
1819 let err = buf
1820 .column_ipv4("v", std::net::Ipv4Addr::new(127, 0, 0, 1))
1821 .unwrap_err();
1822 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1823 assert!(err.msg().contains("column_ipv4"), "{}", err.msg());
1824 }
1825
1826 #[test]
1827 fn buffer_column_date_rejects_ilp_buffer() {
1828 let mut buf = Buffer::new(ProtocolVersion::V2);
1829 buf.table("t").unwrap();
1830 let err = buf.column_date("v", 42).unwrap_err();
1831 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1832 assert!(err.msg().contains("column_date"), "{}", err.msg());
1833 }
1834
1835 #[test]
1836 fn buffer_column_char_rejects_ilp_buffer() {
1837 let mut buf = Buffer::new(ProtocolVersion::V2);
1838 buf.table("t").unwrap();
1839 let err = buf.column_char("v", 0x0041).unwrap_err();
1840 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1841 assert!(err.msg().contains("column_char"), "{}", err.msg());
1842 }
1843
1844 #[test]
1845 fn buffer_column_binary_rejects_ilp_buffer() {
1846 let mut buf = Buffer::new(ProtocolVersion::V2);
1847 buf.table("t").unwrap();
1848 let err = buf.column_binary("v", b"abc").unwrap_err();
1849 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1850 assert!(err.msg().contains("column_binary"), "{}", err.msg());
1851 }
1852
1853 #[test]
1854 fn buffer_column_geohash_rejects_ilp_buffer() {
1855 let mut buf = Buffer::new(ProtocolVersion::V2);
1856 buf.table("t").unwrap();
1857 let err = buf.column_geohash("v", 0xABCD, 16).unwrap_err();
1858 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1859 assert!(err.msg().contains("column_geohash"), "{}", err.msg());
1860 }
1861
1862 #[test]
1863 fn buffer_column_f32_rejects_ilp_buffer() {
1864 let mut buf = Buffer::new(ProtocolVersion::V2);
1865 buf.table("t").unwrap();
1866 let err = buf.column_f32("v", 1.5_f32).unwrap_err();
1867 assert_eq!(err.code(), ErrorCode::InvalidApiCall);
1868 assert!(err.msg().contains("column_f32"), "{}", err.msg());
1869 }
1870
1871 #[test]
1872 fn name_validation_table_name_uses_byte_offset_for_invalid_char() {
1873 let err = match TableName::new("é?") {
1874 Ok(_) => panic!("expected invalid table name"),
1875 Err(err) => err,
1876 };
1877 assert_eq!(err.code(), ErrorCode::InvalidName);
1878 assert_eq!(
1879 err.msg(),
1880 r#"Bad string "é?": Table names can't contain a '?' character, which was found at byte position 2."#
1881 );
1882 }
1883
1884 #[test]
1885 fn name_validation_table_name_rejects_trailing_dot_at_byte_offset() {
1886 let err = match TableName::new("é.") {
1887 Ok(_) => panic!("expected invalid table name"),
1888 Err(err) => err,
1889 };
1890 assert_eq!(err.code(), ErrorCode::InvalidName);
1891 assert_eq!(
1892 err.msg(),
1893 r#"Bad string "é.": Found invalid dot `.` at position 2."#
1894 );
1895 }
1896
1897 #[test]
1898 fn name_validation_column_name_uses_byte_offset_for_invalid_char() {
1899 let err = match ColumnName::new("é?") {
1900 Ok(_) => panic!("expected invalid column name"),
1901 Err(err) => err,
1902 };
1903 assert_eq!(err.code(), ErrorCode::InvalidName);
1904 assert_eq!(
1905 err.msg(),
1906 r#"Bad string "é?": Column names can't contain a '?' character, which was found at byte position 2."#
1907 );
1908 }
1909}