1use crate::DataType;
2use base64::Engine as _;
3use bytes::Bytes;
4use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
5use std::{borrow::Cow, sync::Arc};
6
7#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
11pub enum NGValueCastError {
12 #[error("expected numeric value, got {actual:?}")]
14 NotNumeric { actual: DataType },
15 #[error("numeric value is not finite")]
17 NotFinite,
18 #[error("numeric value out of range for {target}")]
20 OutOfRange { target: &'static str },
21 #[error("type mismatch: expected {expected:?}, got {actual:?}")]
23 TypeMismatch {
24 expected: DataType,
25 actual: DataType,
26 },
27 #[error("failed to parse {target} from string: {value}")]
29 ParseError { target: &'static str, value: String },
30 #[error("binary value is not valid UTF-8 for {target}")]
32 InvalidUtf8 { target: &'static str },
33 #[error("binary length mismatch for {target}: expected {expected} bytes, got {len}")]
35 InvalidBinaryLength {
36 target: &'static str,
37 expected: &'static str,
38 len: usize,
39 },
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
46pub enum BinaryJsonEncoding {
47 Base64,
49 #[default]
53 Hex,
54}
55
56#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
60pub enum TimestampJsonEncoding {
61 #[default]
63 UnixMs,
64 Rfc3339Utc,
68}
69
70#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
74pub struct NGValueJsonOptions {
75 pub binary: BinaryJsonEncoding,
77 pub timestamp: TimestampJsonEncoding,
79}
80
81#[derive(Clone, Debug, PartialEq)]
91pub enum NGValue {
92 Boolean(bool),
93 Int8(i8),
94 UInt8(u8),
95 Int16(i16),
96 UInt16(u16),
97 Int32(i32),
98 UInt32(u32),
99 Int64(i64),
100 UInt64(u64),
101 Float32(f32),
102 Float64(f64),
103 String(Arc<str>),
104 Binary(Bytes),
105 Timestamp(i64),
106}
107
108impl Serialize for NGValue {
121 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122 where
123 S: Serializer,
124 {
125 match self {
126 NGValue::Boolean(v) => serializer.serialize_bool(*v),
127 NGValue::Int8(v) => serializer.serialize_i8(*v),
128 NGValue::UInt8(v) => serializer.serialize_u8(*v),
129 NGValue::Int16(v) => serializer.serialize_i16(*v),
130 NGValue::UInt16(v) => serializer.serialize_u16(*v),
131 NGValue::Int32(v) => serializer.serialize_i32(*v),
132 NGValue::UInt32(v) => serializer.serialize_u32(*v),
133 NGValue::Int64(v) => serializer.serialize_i64(*v),
134 NGValue::UInt64(v) => serializer.serialize_u64(*v),
135 NGValue::Float32(v) => {
136 if v.is_finite() {
137 serializer.serialize_f32(*v)
138 } else {
139 serializer.serialize_unit()
140 }
141 }
142 NGValue::Float64(v) => {
143 if v.is_finite() {
144 serializer.serialize_f64(*v)
145 } else {
146 serializer.serialize_unit()
147 }
148 }
149 NGValue::String(v) => serializer.serialize_str(v.as_ref()),
150 NGValue::Binary(v) => {
151 let s = hex::encode(v.as_ref());
152 serializer.serialize_str(&s)
153 }
154 NGValue::Timestamp(v) => serializer.serialize_i64(*v),
155 }
156 }
157}
158
159impl NGValue {
160 #[inline]
162 pub fn data_type(&self) -> DataType {
163 match self {
164 NGValue::Boolean(_) => DataType::Boolean,
165 NGValue::Int8(_) => DataType::Int8,
166 NGValue::UInt8(_) => DataType::UInt8,
167 NGValue::Int16(_) => DataType::Int16,
168 NGValue::UInt16(_) => DataType::UInt16,
169 NGValue::Int32(_) => DataType::Int32,
170 NGValue::UInt32(_) => DataType::UInt32,
171 NGValue::Int64(_) => DataType::Int64,
172 NGValue::UInt64(_) => DataType::UInt64,
173 NGValue::Float32(_) => DataType::Float32,
174 NGValue::Float64(_) => DataType::Float64,
175 NGValue::String(_) => DataType::String,
176 NGValue::Binary(_) => DataType::Binary,
177 NGValue::Timestamp(_) => DataType::Timestamp,
178 }
179 }
180
181 #[inline]
185 pub fn validate_datatype(&self, expected: DataType) -> bool {
186 self.data_type() == expected
187 }
188
189 pub fn to_json_value(&self, opts: NGValueJsonOptions) -> serde_json::Value {
194 match self {
195 NGValue::Boolean(v) => serde_json::Value::Bool(*v),
196 NGValue::Int8(v) => serde_json::Value::Number((*v as i64).into()),
197 NGValue::UInt8(v) => serde_json::Value::Number((*v as u64).into()),
198 NGValue::Int16(v) => serde_json::Value::Number((*v as i64).into()),
199 NGValue::UInt16(v) => serde_json::Value::Number((*v as u64).into()),
200 NGValue::Int32(v) => serde_json::Value::Number((*v as i64).into()),
201 NGValue::UInt32(v) => serde_json::Value::Number((*v as u64).into()),
202 NGValue::Int64(v) => serde_json::Value::Number((*v).into()),
203 NGValue::UInt64(v) => serde_json::Value::Number((*v).into()),
204 NGValue::Float32(v) => {
205 serde_json::Number::from_f64(*v as f64).map_or(serde_json::Value::Null, Into::into)
206 }
207 NGValue::Float64(v) => {
208 serde_json::Number::from_f64(*v).map_or(serde_json::Value::Null, Into::into)
209 }
210 NGValue::String(v) => serde_json::Value::String(v.to_string()),
211 NGValue::Binary(v) => {
212 let s = match opts.binary {
213 BinaryJsonEncoding::Base64 => {
214 base64::engine::general_purpose::STANDARD.encode(v.as_ref())
215 }
216 BinaryJsonEncoding::Hex => hex::encode(v.as_ref()),
217 };
218 serde_json::Value::String(s)
219 }
220 NGValue::Timestamp(v) => match opts.timestamp {
221 TimestampJsonEncoding::UnixMs => serde_json::Value::Number((*v).into()),
222 TimestampJsonEncoding::Rfc3339Utc => {
223 match chrono::DateTime::<chrono::Utc>::from_timestamp_millis(*v) {
225 Some(dt) => serde_json::Value::String(dt.to_rfc3339()),
226 None => serde_json::Value::Number((*v).into()),
227 }
228 }
229 },
230 }
231 }
232
233 #[inline]
249 pub fn try_from_json_scalar(expected: DataType, v: &serde_json::Value) -> Option<Self> {
250 match expected {
251 DataType::Boolean => {
252 if let Some(b) = v.as_bool() {
253 return Some(NGValue::Boolean(b));
254 }
255 if let Some(i) = v.as_i64() {
256 return Some(NGValue::Boolean(i != 0));
257 }
258 if let Some(u) = v.as_u64() {
259 return Some(NGValue::Boolean(u != 0));
260 }
261 None
262 }
263 DataType::Int8 => v
264 .as_i64()
265 .and_then(|n| i8::try_from(n).ok())
266 .map(NGValue::Int8),
267 DataType::UInt8 => v
268 .as_u64()
269 .and_then(|n| u8::try_from(n).ok())
270 .map(NGValue::UInt8),
271 DataType::Int16 => v
272 .as_i64()
273 .and_then(|n| i16::try_from(n).ok())
274 .map(NGValue::Int16),
275 DataType::UInt16 => v
276 .as_u64()
277 .and_then(|n| u16::try_from(n).ok())
278 .map(NGValue::UInt16),
279 DataType::Int32 => v
280 .as_i64()
281 .and_then(|n| i32::try_from(n).ok())
282 .map(NGValue::Int32),
283 DataType::UInt32 => v
284 .as_u64()
285 .and_then(|n| u32::try_from(n).ok())
286 .map(NGValue::UInt32),
287 DataType::Int64 => v.as_i64().map(NGValue::Int64),
288 DataType::UInt64 => v.as_u64().map(NGValue::UInt64),
289 DataType::Float32 => v.as_f64().map(|n| NGValue::Float32(n as f32)),
290 DataType::Float64 => v.as_f64().map(NGValue::Float64),
291 DataType::String => v.as_str().map(|s| NGValue::String(Arc::<str>::from(s))),
292 DataType::Binary => {
293 let s = v.as_str()?;
294 let st = s.trim();
295 let bytes = if st.starts_with("0x") || st.starts_with("0X") {
297 let hex = &st[2..];
298 if hex.is_empty() {
299 Vec::new()
300 } else {
301 hex::decode(hex).ok()?
302 }
303 } else {
304 base64::engine::general_purpose::STANDARD.decode(st).ok()?
306 };
307 Some(NGValue::Binary(Bytes::from(bytes)))
308 }
309 DataType::Timestamp => {
310 if let Some(i) = v.as_i64() {
311 return Some(NGValue::Timestamp(i));
312 }
313 if let Some(u) = v.as_u64() {
314 return Some(NGValue::Timestamp(u as i64));
315 }
316 if let Some(s) = v.as_str() {
317 if let Ok(dt) = chrono::DateTime::parse_from_rfc3339(s.trim()) {
318 return Some(NGValue::Timestamp(dt.timestamp_millis()));
319 }
320 }
321 None
322 }
323 }
324 }
325}
326
327#[inline]
333fn parse_bool_from_str(s: &str) -> Option<bool> {
334 let st = s.trim().to_ascii_lowercase();
335 match st.as_str() {
336 "true" | "1" | "on" | "yes" | "y" | "t" => Some(true),
337 "false" | "0" | "off" | "no" | "n" | "f" => Some(false),
338 _ => None,
339 }
340}
341
342#[inline]
343fn binary_len_err(target: &'static str, expected: &'static str, len: usize) -> NGValueCastError {
344 NGValueCastError::InvalidBinaryLength {
345 target,
346 expected,
347 len,
348 }
349}
350
351#[inline]
352fn binary_to_u8(b: &Bytes, target: &'static str) -> Result<u8, NGValueCastError> {
353 if !b.is_empty() {
354 Ok(b[0])
355 } else {
356 Err(binary_len_err(target, "1", b.len()))
357 }
358}
359
360#[inline]
361fn binary_to_i8(b: &Bytes, target: &'static str) -> Result<i8, NGValueCastError> {
362 if !b.is_empty() {
363 Ok(i8::from_be_bytes([b[0]]))
364 } else {
365 Err(binary_len_err(target, "1", b.len()))
366 }
367}
368
369#[inline]
370fn binary_to_i16_be(b: &Bytes, target: &'static str) -> Result<i16, NGValueCastError> {
371 if b.len() >= 2 {
372 Ok(i16::from_be_bytes([b[0], b[1]]))
373 } else {
374 Err(binary_len_err(target, "2", b.len()))
375 }
376}
377
378#[inline]
379fn binary_to_i32_be(b: &Bytes, target: &'static str) -> Result<i32, NGValueCastError> {
380 if b.len() >= 4 {
381 Ok(i32::from_be_bytes([b[0], b[1], b[2], b[3]]))
382 } else {
383 Err(binary_len_err(target, "4", b.len()))
384 }
385}
386
387#[inline]
388fn binary_to_i64_be(b: &Bytes, target: &'static str) -> Result<i64, NGValueCastError> {
389 if b.len() >= 8 {
390 Ok(i64::from_be_bytes([
391 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
392 ]))
393 } else {
394 Err(binary_len_err(target, "8", b.len()))
395 }
396}
397
398#[inline]
399fn binary_to_u16_be(b: &Bytes, target: &'static str) -> Result<u16, NGValueCastError> {
400 if b.len() >= 2 {
401 Ok(u16::from_be_bytes([b[0], b[1]]))
402 } else {
403 Err(binary_len_err(target, "2", b.len()))
404 }
405}
406
407#[inline]
408fn binary_to_u32_be(b: &Bytes, target: &'static str) -> Result<u32, NGValueCastError> {
409 if b.len() >= 4 {
410 Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
411 } else {
412 Err(binary_len_err(target, "4", b.len()))
413 }
414}
415
416#[inline]
417fn binary_to_u64_be(b: &Bytes, target: &'static str) -> Result<u64, NGValueCastError> {
418 if b.len() >= 8 {
419 Ok(u64::from_be_bytes([
420 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
421 ]))
422 } else {
423 Err(binary_len_err(target, "8", b.len()))
424 }
425}
426
427#[inline]
428fn parse_f64_from_str(target: &'static str, s: &str) -> Result<f64, NGValueCastError> {
429 let st = s.trim();
430 if st.is_empty() {
431 return Err(NGValueCastError::ParseError {
432 target,
433 value: st.to_string(),
434 });
435 }
436
437 let parsed = if let Some(hex) = st.strip_prefix("0x").or(st.strip_prefix("0X")) {
439 let n = u64::from_str_radix(hex.trim(), 16).map_err(|_| NGValueCastError::ParseError {
440 target,
441 value: st.to_string(),
442 })?;
443 n as f64
444 } else {
445 st.parse::<f64>()
446 .map_err(|_| NGValueCastError::ParseError {
447 target,
448 value: st.to_string(),
449 })?
450 };
451
452 if !parsed.is_finite() {
453 return Err(NGValueCastError::NotFinite);
454 }
455 Ok(parsed)
456}
457
458#[inline]
459fn parse_i64_from_str(target: &'static str, s: &str) -> Result<i64, NGValueCastError> {
460 let st = s.trim();
461 if st.is_empty() {
462 return Err(NGValueCastError::ParseError {
463 target,
464 value: st.to_string(),
465 });
466 }
467
468 if let Ok(n) = st.parse::<i64>() {
470 return Ok(n);
471 }
472
473 let (sign, rest) = match st.as_bytes().first().copied() {
475 Some(b'+') => (1i128, &st[1..]),
476 Some(b'-') => (-1i128, &st[1..]),
477 _ => (1i128, st),
478 };
479 if let Some(hex) = rest.strip_prefix("0x").or(rest.strip_prefix("0X")) {
480 let u = u64::from_str_radix(hex.trim(), 16).map_err(|_| NGValueCastError::ParseError {
481 target,
482 value: st.to_string(),
483 })? as i128;
484 let signed = sign * u;
485 if signed < i64::MIN as i128 || signed > i64::MAX as i128 {
486 return Err(NGValueCastError::OutOfRange { target });
487 }
488 return Ok(signed as i64);
489 }
490
491 let f = parse_f64_from_str(target, st)?;
493 let r = f.round();
494 if r < i64::MIN as f64 || r > i64::MAX as f64 {
495 return Err(NGValueCastError::OutOfRange { target });
496 }
497 Ok(r as i64)
498}
499
500#[inline]
501fn parse_u64_from_str(target: &'static str, s: &str) -> Result<u64, NGValueCastError> {
502 let st = s.trim();
503 if st.is_empty() {
504 return Err(NGValueCastError::ParseError {
505 target,
506 value: st.to_string(),
507 });
508 }
509
510 if let Ok(n) = st.parse::<u64>() {
512 return Ok(n);
513 }
514
515 if let Some(hex) = st.strip_prefix("0x").or(st.strip_prefix("0X")) {
517 return u64::from_str_radix(hex.trim(), 16).map_err(|_| NGValueCastError::ParseError {
518 target,
519 value: st.to_string(),
520 });
521 }
522
523 let f = parse_f64_from_str(target, st)?;
525 let r = f.round();
526 if r < 0.0 || r > u64::MAX as f64 {
527 return Err(NGValueCastError::OutOfRange { target });
528 }
529 Ok(r as u64)
530}
531
532impl TryFrom<&NGValue> for bool {
533 type Error = NGValueCastError;
534
535 #[inline]
536 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
537 match v {
538 NGValue::Boolean(b) => Ok(*b),
539 NGValue::Int8(x) => Ok(*x != 0),
541 NGValue::UInt8(x) => Ok(*x != 0),
542 NGValue::Int16(x) => Ok(*x != 0),
543 NGValue::UInt16(x) => Ok(*x != 0),
544 NGValue::Int32(x) => Ok(*x != 0),
545 NGValue::UInt32(x) => Ok(*x != 0),
546 NGValue::Int64(x) => Ok(*x != 0),
547 NGValue::UInt64(x) => Ok(*x != 0),
548 NGValue::Float32(x) => {
549 let f = *x as f64;
550 if !f.is_finite() {
551 return Err(NGValueCastError::NotFinite);
552 }
553 Ok(f != 0.0)
554 }
555 NGValue::Float64(x) => {
556 if !x.is_finite() {
557 return Err(NGValueCastError::NotFinite);
558 }
559 Ok(*x != 0.0)
560 }
561 NGValue::Timestamp(ms) => Ok(*ms != 0),
562 NGValue::String(s) => {
563 parse_bool_from_str(s.as_ref()).ok_or(NGValueCastError::ParseError {
564 target: "bool",
565 value: s.to_string(),
566 })
567 }
568 NGValue::Binary(b) => Ok(b.as_ref().iter().any(|x| *x != 0)),
572 }
573 }
574}
575
576impl TryFrom<&NGValue> for i8 {
577 type Error = NGValueCastError;
578
579 #[inline]
580 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
581 match v {
582 NGValue::Boolean(x) => Ok(if *x { 1 } else { 0 }),
583 NGValue::Int8(x) => Ok(*x),
584 NGValue::UInt8(x) => {
585 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
586 }
587 NGValue::Int16(x) => {
588 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
589 }
590 NGValue::UInt16(x) => {
591 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
592 }
593 NGValue::Int32(x) => {
594 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
595 }
596 NGValue::UInt32(x) => {
597 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
598 }
599 NGValue::Int64(x) => {
600 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
601 }
602 NGValue::UInt64(x) => {
603 i8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
604 }
605 NGValue::Float32(x) => {
606 let r = (*x as f64).round();
607 if !r.is_finite() {
608 return Err(NGValueCastError::NotFinite);
609 }
610 if r >= i8::MIN as f64 && r <= i8::MAX as f64 {
611 Ok(r as i8)
612 } else {
613 Err(NGValueCastError::OutOfRange { target: "i8" })
614 }
615 }
616 NGValue::Float64(x) => {
617 let r = x.round();
618 if !r.is_finite() {
619 return Err(NGValueCastError::NotFinite);
620 }
621 if r >= i8::MIN as f64 && r <= i8::MAX as f64 {
622 Ok(r as i8)
623 } else {
624 Err(NGValueCastError::OutOfRange { target: "i8" })
625 }
626 }
627 NGValue::Timestamp(ms) => {
628 i8::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
629 }
630 NGValue::String(s) => {
631 let n = parse_i64_from_str("i8", s.as_ref())?;
632 i8::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "i8" })
633 }
634 NGValue::Binary(b) => binary_to_i8(b, "i8"),
635 }
636 }
637}
638
639impl TryFrom<&NGValue> for u8 {
640 type Error = NGValueCastError;
641
642 #[inline]
643 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
644 match v {
645 NGValue::Boolean(x) => {
646 if *x {
647 Ok(1)
648 } else {
649 Ok(0)
650 }
651 }
652 NGValue::UInt8(x) => Ok(*x),
653 NGValue::Int8(x) => {
654 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
655 }
656 NGValue::UInt16(x) => {
657 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
658 }
659 NGValue::Int16(x) => {
660 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
661 }
662 NGValue::UInt32(x) => {
663 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
664 }
665 NGValue::Int32(x) => {
666 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
667 }
668 NGValue::UInt64(x) => {
669 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
670 }
671 NGValue::Int64(x) => {
672 u8::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
673 }
674 NGValue::Float32(x) => {
675 let r = (*x as f64).round();
676 if !r.is_finite() {
677 return Err(NGValueCastError::NotFinite);
678 }
679 if r >= 0.0 && r <= u8::MAX as f64 {
680 Ok(r as u8)
681 } else {
682 Err(NGValueCastError::OutOfRange { target: "u8" })
683 }
684 }
685 NGValue::Float64(x) => {
686 let r = x.round();
687 if !r.is_finite() {
688 return Err(NGValueCastError::NotFinite);
689 }
690 if r >= 0.0 && r <= u8::MAX as f64 {
691 Ok(r as u8)
692 } else {
693 Err(NGValueCastError::OutOfRange { target: "u8" })
694 }
695 }
696 NGValue::Timestamp(ms) => {
697 u8::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
698 }
699 NGValue::String(s) => {
700 let n = parse_u64_from_str("u8", s.as_ref())?;
701 u8::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "u8" })
702 }
703 NGValue::Binary(b) => binary_to_u8(b, "u8"),
704 }
705 }
706}
707
708impl TryFrom<&NGValue> for u16 {
709 type Error = NGValueCastError;
710
711 #[inline]
712 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
713 match v {
714 NGValue::Boolean(x) => Ok(if *x { 1 } else { 0 }),
715 NGValue::UInt16(x) => Ok(*x),
716 NGValue::UInt8(x) => Ok(*x as u16),
717 NGValue::Int8(x) => {
718 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
719 }
720 NGValue::Int16(x) => {
721 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
722 }
723 NGValue::Int32(x) => {
724 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
725 }
726 NGValue::UInt32(x) => {
727 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
728 }
729 NGValue::Int64(x) => {
730 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
731 }
732 NGValue::UInt64(x) => {
733 u16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
734 }
735 NGValue::Float32(x) => {
736 let r = (*x as f64).round();
737 if !r.is_finite() {
738 return Err(NGValueCastError::NotFinite);
739 }
740 if r >= 0.0 && r <= u16::MAX as f64 {
741 Ok(r as u16)
742 } else {
743 Err(NGValueCastError::OutOfRange { target: "u16" })
744 }
745 }
746 NGValue::Float64(x) => {
747 let r = x.round();
748 if !r.is_finite() {
749 return Err(NGValueCastError::NotFinite);
750 }
751 if r >= 0.0 && r <= u16::MAX as f64 {
752 Ok(r as u16)
753 } else {
754 Err(NGValueCastError::OutOfRange { target: "u16" })
755 }
756 }
757 NGValue::Timestamp(ms) => {
758 u16::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
759 }
760 NGValue::String(s) => {
761 let n = parse_u64_from_str("u16", s.as_ref())?;
762 u16::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "u16" })
763 }
764 NGValue::Binary(b) => binary_to_u16_be(b, "u16"),
765 }
766 }
767}
768
769impl TryFrom<&NGValue> for i16 {
770 type Error = NGValueCastError;
771
772 #[inline]
773 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
774 match v {
775 NGValue::Boolean(x) => {
776 if *x {
777 Ok(1)
778 } else {
779 Ok(0)
780 }
781 }
782 NGValue::Int16(x) => Ok(*x),
783 NGValue::Int8(x) => Ok(*x as i16),
784 NGValue::UInt8(x) => Ok(*x as i16),
785 NGValue::UInt16(x) => {
786 i16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
787 }
788 NGValue::Int32(x) => {
789 i16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
790 }
791 NGValue::UInt32(x) => {
792 i16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
793 }
794 NGValue::Int64(x) => {
795 i16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
796 }
797 NGValue::UInt64(x) => {
798 i16::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
799 }
800 NGValue::Float32(x) => {
801 let r = (*x as f64).round();
802 if !r.is_finite() {
803 return Err(NGValueCastError::NotFinite);
804 }
805 if r >= i16::MIN as f64 && r <= i16::MAX as f64 {
806 Ok(r as i16)
807 } else {
808 Err(NGValueCastError::OutOfRange { target: "i16" })
809 }
810 }
811 NGValue::Float64(x) => {
812 let r = x.round();
813 if !r.is_finite() {
814 return Err(NGValueCastError::NotFinite);
815 }
816 if r >= i16::MIN as f64 && r <= i16::MAX as f64 {
817 Ok(r as i16)
818 } else {
819 Err(NGValueCastError::OutOfRange { target: "i16" })
820 }
821 }
822 NGValue::Timestamp(ms) => {
823 i16::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
824 }
825 NGValue::String(s) => {
826 let n = parse_i64_from_str("i16", s.as_ref())?;
827 i16::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "i16" })
828 }
829 NGValue::Binary(b) => binary_to_i16_be(b, "i16"),
830 }
831 }
832}
833
834impl TryFrom<&NGValue> for i32 {
835 type Error = NGValueCastError;
836
837 #[inline]
838 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
839 match v {
840 NGValue::Boolean(x) => {
841 if *x {
842 Ok(1)
843 } else {
844 Ok(0)
845 }
846 }
847 NGValue::Int32(x) => Ok(*x),
848 NGValue::Int16(x) => Ok(*x as i32),
849 NGValue::Int8(x) => Ok(*x as i32),
850 NGValue::UInt8(x) => Ok(*x as i32),
851 NGValue::UInt16(x) => Ok(*x as i32),
852 NGValue::UInt32(x) => {
853 i32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i32" })
854 }
855 NGValue::Int64(x) => {
856 i32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i32" })
857 }
858 NGValue::UInt64(x) => {
859 i32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i32" })
860 }
861 NGValue::Float32(x) => {
862 let r = (*x as f64).round();
863 if !r.is_finite() {
864 return Err(NGValueCastError::NotFinite);
865 }
866 if r >= i32::MIN as f64 && r <= i32::MAX as f64 {
867 Ok(r as i32)
868 } else {
869 Err(NGValueCastError::OutOfRange { target: "i32" })
870 }
871 }
872 NGValue::Float64(x) => {
873 let r = x.round();
874 if !r.is_finite() {
875 return Err(NGValueCastError::NotFinite);
876 }
877 if r >= i32::MIN as f64 && r <= i32::MAX as f64 {
878 Ok(r as i32)
879 } else {
880 Err(NGValueCastError::OutOfRange { target: "i32" })
881 }
882 }
883 NGValue::Timestamp(ms) => {
884 i32::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "i32" })
885 }
886 NGValue::String(s) => {
887 let n = parse_i64_from_str("i32", s.as_ref())?;
888 i32::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "i32" })
889 }
890 NGValue::Binary(b) => binary_to_i32_be(b, "i32"),
891 }
892 }
893}
894
895impl TryFrom<&NGValue> for u32 {
896 type Error = NGValueCastError;
897
898 #[inline]
899 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
900 match v {
901 NGValue::Boolean(x) => Ok(if *x { 1 } else { 0 }),
902 NGValue::UInt32(x) => Ok(*x),
903 NGValue::UInt16(x) => Ok(*x as u32),
904 NGValue::UInt8(x) => Ok(*x as u32),
905 NGValue::Int8(x) => {
906 u32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
907 }
908 NGValue::Int16(x) => {
909 u32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
910 }
911 NGValue::Int32(x) => {
912 u32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
913 }
914 NGValue::Int64(x) => {
915 u32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
916 }
917 NGValue::UInt64(x) => {
918 u32::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
919 }
920 NGValue::Float32(x) => {
921 let r = (*x as f64).round();
922 if !r.is_finite() {
923 return Err(NGValueCastError::NotFinite);
924 }
925 if r >= 0.0 && r <= u32::MAX as f64 {
926 Ok(r as u32)
927 } else {
928 Err(NGValueCastError::OutOfRange { target: "u32" })
929 }
930 }
931 NGValue::Float64(x) => {
932 let r = x.round();
933 if !r.is_finite() {
934 return Err(NGValueCastError::NotFinite);
935 }
936 if r >= 0.0 && r <= u32::MAX as f64 {
937 Ok(r as u32)
938 } else {
939 Err(NGValueCastError::OutOfRange { target: "u32" })
940 }
941 }
942 NGValue::Timestamp(ms) => {
943 u32::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
944 }
945 NGValue::String(s) => {
946 let n = parse_u64_from_str("u32", s.as_ref())?;
947 u32::try_from(n).map_err(|_| NGValueCastError::OutOfRange { target: "u32" })
948 }
949 NGValue::Binary(b) => binary_to_u32_be(b, "u32"),
950 }
951 }
952}
953
954impl TryFrom<&NGValue> for i64 {
955 type Error = NGValueCastError;
956
957 #[inline]
958 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
959 match v {
960 NGValue::Boolean(x) => {
961 if *x {
962 Ok(1)
963 } else {
964 Ok(0)
965 }
966 }
967 NGValue::Int64(x) => Ok(*x),
968 NGValue::Int32(x) => Ok(*x as i64),
969 NGValue::Int16(x) => Ok(*x as i64),
970 NGValue::Int8(x) => Ok(*x as i64),
971 NGValue::UInt8(x) => Ok(*x as i64),
972 NGValue::UInt16(x) => Ok(*x as i64),
973 NGValue::UInt32(x) => Ok(*x as i64),
974 NGValue::UInt64(x) => {
975 i64::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "i64" })
976 }
977 NGValue::Float32(x) => {
978 let r = (*x as f64).round();
979 if !r.is_finite() {
980 return Err(NGValueCastError::NotFinite);
981 }
982 if r >= i64::MIN as f64 && r <= i64::MAX as f64 {
983 Ok(r as i64)
984 } else {
985 Err(NGValueCastError::OutOfRange { target: "i64" })
986 }
987 }
988 NGValue::Float64(x) => {
989 let r = x.round();
990 if !r.is_finite() {
991 return Err(NGValueCastError::NotFinite);
992 }
993 if r >= i64::MIN as f64 && r <= i64::MAX as f64 {
994 Ok(r as i64)
995 } else {
996 Err(NGValueCastError::OutOfRange { target: "i64" })
997 }
998 }
999 NGValue::Timestamp(ms) => Ok(*ms),
1000 NGValue::String(s) => parse_i64_from_str("i64", s.as_ref()),
1001 NGValue::Binary(b) => binary_to_i64_be(b, "i64"),
1002 }
1003 }
1004}
1005
1006impl TryFrom<&NGValue> for u64 {
1007 type Error = NGValueCastError;
1008
1009 #[inline]
1010 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1011 match v {
1012 NGValue::Boolean(x) => {
1013 if *x {
1014 Ok(1)
1015 } else {
1016 Ok(0)
1017 }
1018 }
1019 NGValue::UInt64(x) => Ok(*x),
1020 NGValue::UInt32(x) => Ok(*x as u64),
1021 NGValue::UInt16(x) => Ok(*x as u64),
1022 NGValue::UInt8(x) => Ok(*x as u64),
1023 NGValue::Int8(x) => {
1024 u64::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u64" })
1025 }
1026 NGValue::Int16(x) => {
1027 u64::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u64" })
1028 }
1029 NGValue::Int32(x) => {
1030 u64::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u64" })
1031 }
1032 NGValue::Int64(x) => {
1033 u64::try_from(*x).map_err(|_| NGValueCastError::OutOfRange { target: "u64" })
1034 }
1035 NGValue::Float32(x) => {
1036 let r = (*x as f64).round();
1037 if !r.is_finite() {
1038 return Err(NGValueCastError::NotFinite);
1039 }
1040 if r >= 0.0 && r <= u64::MAX as f64 {
1041 Ok(r as u64)
1042 } else {
1043 Err(NGValueCastError::OutOfRange { target: "u64" })
1044 }
1045 }
1046 NGValue::Float64(x) => {
1047 let r = x.round();
1048 if !r.is_finite() {
1049 return Err(NGValueCastError::NotFinite);
1050 }
1051 if r >= 0.0 && r <= u64::MAX as f64 {
1052 Ok(r as u64)
1053 } else {
1054 Err(NGValueCastError::OutOfRange { target: "u64" })
1055 }
1056 }
1057 NGValue::Timestamp(ms) => {
1058 u64::try_from(*ms).map_err(|_| NGValueCastError::OutOfRange { target: "u64" })
1059 }
1060 NGValue::String(s) => parse_u64_from_str("u64", s.as_ref()),
1061 NGValue::Binary(b) => binary_to_u64_be(b, "u64"),
1062 }
1063 }
1064}
1065
1066impl TryFrom<&NGValue> for f64 {
1067 type Error = NGValueCastError;
1068
1069 #[inline]
1070 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1071 let f = match v {
1072 NGValue::Boolean(x) => {
1073 if *x {
1074 1.0
1075 } else {
1076 0.0
1077 }
1078 }
1079 NGValue::Int8(x) => *x as f64,
1080 NGValue::UInt8(x) => *x as f64,
1081 NGValue::Int16(x) => *x as f64,
1082 NGValue::UInt16(x) => *x as f64,
1083 NGValue::Int32(x) => *x as f64,
1084 NGValue::UInt32(x) => *x as f64,
1085 NGValue::Int64(x) => *x as f64,
1086 NGValue::UInt64(x) => *x as f64,
1087 NGValue::Float32(x) => *x as f64,
1088 NGValue::Float64(x) => *x,
1089 NGValue::Timestamp(ms) => *ms as f64,
1090 NGValue::String(s) => parse_f64_from_str("f64", s.as_ref())?,
1091 NGValue::Binary(b) => match b.len() {
1092 4 => {
1093 let f = f32::from_be_bytes([b[0], b[1], b[2], b[3]]);
1094 f as f64
1095 }
1096 8 => f64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]),
1097 other => return Err(binary_len_err("f64", "4 or 8", other)),
1098 },
1099 };
1100
1101 if !f.is_finite() {
1102 return Err(NGValueCastError::NotFinite);
1103 }
1104 Ok(f)
1105 }
1106}
1107
1108impl TryFrom<&NGValue> for f32 {
1109 type Error = NGValueCastError;
1110
1111 #[inline]
1112 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1113 let f = f64::try_from(v)?;
1114 if f < f32::MIN as f64 || f > f32::MAX as f64 {
1116 return Err(NGValueCastError::OutOfRange { target: "f32" });
1117 }
1118 Ok(f as f32)
1119 }
1120}
1121
1122impl TryFrom<&NGValue> for String {
1123 type Error = NGValueCastError;
1124
1125 #[inline]
1126 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1127 match v {
1128 NGValue::String(s) => Ok(s.to_string()),
1129 NGValue::Binary(b) => Ok(base64::engine::general_purpose::STANDARD.encode(b.as_ref())),
1130 NGValue::Timestamp(ms) => {
1131 match chrono::DateTime::<chrono::Utc>::from_timestamp_millis(*ms) {
1132 Some(dt) => Ok(dt.to_rfc3339()),
1133 None => Ok(ms.to_string()),
1134 }
1135 }
1136 NGValue::Boolean(b) => Ok(b.to_string()),
1137 NGValue::Int8(n) => Ok(n.to_string()),
1138 NGValue::UInt8(n) => Ok(n.to_string()),
1139 NGValue::Int16(n) => Ok(n.to_string()),
1140 NGValue::UInt16(n) => Ok(n.to_string()),
1141 NGValue::Int32(n) => Ok(n.to_string()),
1142 NGValue::UInt32(n) => Ok(n.to_string()),
1143 NGValue::Int64(n) => Ok(n.to_string()),
1144 NGValue::UInt64(n) => Ok(n.to_string()),
1145 NGValue::Float32(n) => Ok(n.to_string()),
1146 NGValue::Float64(n) => Ok(n.to_string()),
1147 }
1148 }
1149}
1150
1151impl<'a> TryFrom<&'a NGValue> for Cow<'a, str> {
1156 type Error = NGValueCastError;
1157
1158 #[inline]
1159 fn try_from(v: &'a NGValue) -> Result<Self, Self::Error> {
1160 Ok(match v {
1161 NGValue::String(s) => Cow::Borrowed(s.as_ref()),
1162 NGValue::Binary(b) => {
1163 Cow::Owned(base64::engine::general_purpose::STANDARD.encode(b.as_ref()))
1164 }
1165 NGValue::Timestamp(ms) => {
1166 match chrono::DateTime::<chrono::Utc>::from_timestamp_millis(*ms) {
1167 Some(dt) => Cow::Owned(dt.to_rfc3339()),
1168 None => Cow::Owned(ms.to_string()),
1169 }
1170 }
1171 NGValue::Boolean(b) => Cow::Owned(b.to_string()),
1172 NGValue::Int8(n) => Cow::Owned(n.to_string()),
1173 NGValue::UInt8(n) => Cow::Owned(n.to_string()),
1174 NGValue::Int16(n) => Cow::Owned(n.to_string()),
1175 NGValue::UInt16(n) => Cow::Owned(n.to_string()),
1176 NGValue::Int32(n) => Cow::Owned(n.to_string()),
1177 NGValue::UInt32(n) => Cow::Owned(n.to_string()),
1178 NGValue::Int64(n) => Cow::Owned(n.to_string()),
1179 NGValue::UInt64(n) => Cow::Owned(n.to_string()),
1180 NGValue::Float32(n) => Cow::Owned(n.to_string()),
1181 NGValue::Float64(n) => Cow::Owned(n.to_string()),
1182 })
1183 }
1184}
1185
1186impl TryFrom<&NGValue> for Bytes {
1187 type Error = NGValueCastError;
1188
1189 #[inline]
1194 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1195 Ok(match v {
1196 NGValue::Binary(b) => b.clone(),
1197 NGValue::String(s) => Bytes::copy_from_slice(s.as_ref().as_bytes()),
1198 NGValue::Boolean(b) => Bytes::from(vec![if *b { 1 } else { 0 }]),
1199 NGValue::Int8(n) => Bytes::from(vec![*n as u8]),
1200 NGValue::UInt8(n) => Bytes::from(vec![*n]),
1201 NGValue::Int16(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1202 NGValue::UInt16(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1203 NGValue::Int32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1204 NGValue::UInt32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1205 NGValue::Int64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1206 NGValue::UInt64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1207 NGValue::Float32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1208 NGValue::Float64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1209 NGValue::Timestamp(ms) => Bytes::copy_from_slice(&ms.to_be_bytes()),
1210 })
1211 }
1212}
1213
1214impl TryFrom<&NGValue> for Vec<u8> {
1215 type Error = NGValueCastError;
1216
1217 #[inline]
1221 fn try_from(v: &NGValue) -> Result<Self, Self::Error> {
1222 Ok(match v {
1223 NGValue::Binary(b) => b.as_ref().to_vec(),
1224 NGValue::String(s) => s.as_ref().as_bytes().to_vec(),
1225 NGValue::Boolean(b) => vec![if *b { 1 } else { 0 }],
1226 NGValue::Int8(n) => vec![*n as u8],
1227 NGValue::UInt8(n) => vec![*n],
1228 NGValue::Int16(n) => n.to_be_bytes().to_vec(),
1229 NGValue::UInt16(n) => n.to_be_bytes().to_vec(),
1230 NGValue::Int32(n) => n.to_be_bytes().to_vec(),
1231 NGValue::UInt32(n) => n.to_be_bytes().to_vec(),
1232 NGValue::Int64(n) => n.to_be_bytes().to_vec(),
1233 NGValue::UInt64(n) => n.to_be_bytes().to_vec(),
1234 NGValue::Float32(n) => n.to_be_bytes().to_vec(),
1235 NGValue::Float64(n) => n.to_be_bytes().to_vec(),
1236 NGValue::Timestamp(ms) => ms.to_be_bytes().to_vec(),
1237 })
1238 }
1239}
1240
1241impl TryFrom<NGValue> for Bytes {
1242 type Error = NGValueCastError;
1243
1244 #[inline]
1246 fn try_from(v: NGValue) -> Result<Self, Self::Error> {
1247 Ok(match v {
1248 NGValue::Binary(b) => b,
1249 NGValue::String(s) => Bytes::copy_from_slice(s.as_ref().as_bytes()),
1250 NGValue::Boolean(b) => Bytes::from(vec![if b { 1 } else { 0 }]),
1251 NGValue::Int8(n) => Bytes::from(vec![n as u8]),
1252 NGValue::UInt8(n) => Bytes::from(vec![n]),
1253 NGValue::Int16(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1254 NGValue::UInt16(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1255 NGValue::Int32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1256 NGValue::UInt32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1257 NGValue::Int64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1258 NGValue::UInt64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1259 NGValue::Float32(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1260 NGValue::Float64(n) => Bytes::copy_from_slice(&n.to_be_bytes()),
1261 NGValue::Timestamp(ms) => Bytes::copy_from_slice(&ms.to_be_bytes()),
1262 })
1263 }
1264}
1265
1266impl TryFrom<NGValue> for Vec<u8> {
1267 type Error = NGValueCastError;
1268
1269 #[inline]
1271 fn try_from(v: NGValue) -> Result<Self, Self::Error> {
1272 Ok(match v {
1273 NGValue::Binary(b) => b.as_ref().to_vec(),
1274 NGValue::String(s) => s.as_ref().as_bytes().to_vec(),
1275 NGValue::Boolean(b) => vec![if b { 1 } else { 0 }],
1276 NGValue::Int8(n) => vec![n as u8],
1277 NGValue::UInt8(n) => vec![n],
1278 NGValue::Int16(n) => n.to_be_bytes().to_vec(),
1279 NGValue::UInt16(n) => n.to_be_bytes().to_vec(),
1280 NGValue::Int32(n) => n.to_be_bytes().to_vec(),
1281 NGValue::UInt32(n) => n.to_be_bytes().to_vec(),
1282 NGValue::Int64(n) => n.to_be_bytes().to_vec(),
1283 NGValue::UInt64(n) => n.to_be_bytes().to_vec(),
1284 NGValue::Float32(n) => n.to_be_bytes().to_vec(),
1285 NGValue::Float64(n) => n.to_be_bytes().to_vec(),
1286 NGValue::Timestamp(ms) => ms.to_be_bytes().to_vec(),
1287 })
1288 }
1289}
1290
1291impl<'de> Deserialize<'de> for NGValue {
1292 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1293 where
1294 D: Deserializer<'de>,
1295 {
1296 let v = serde_json::Value::deserialize(deserializer)?;
1299 match v {
1300 serde_json::Value::Bool(b) => Ok(NGValue::Boolean(b)),
1301 serde_json::Value::Number(n) => {
1302 if let Some(i) = n.as_i64() {
1303 Ok(NGValue::Int64(i))
1304 } else if let Some(u) = n.as_u64() {
1305 Ok(NGValue::UInt64(u))
1306 } else if let Some(f) = n.as_f64() {
1307 Ok(NGValue::Float64(f))
1308 } else {
1309 Err(de::Error::custom("invalid JSON number"))
1310 }
1311 }
1312 serde_json::Value::String(s) => Ok(NGValue::String(Arc::<str>::from(s))),
1313 serde_json::Value::Null => {
1314 Err(de::Error::custom("null cannot be converted to NGValue"))
1315 }
1316 serde_json::Value::Array(_) | serde_json::Value::Object(_) => Err(de::Error::custom(
1317 "array/object cannot be converted to NGValue without type information",
1318 )),
1319 }
1320 }
1321}
1322
1323#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1327pub struct PointValue {
1328 pub point_id: i32,
1330 pub point_key: Arc<str>,
1332 pub value: NGValue,
1334}