use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use crate::client::Payload;
#[allow(deprecated)]
use crate::error::NotA;
use crate::prelude::{PointStruct, Value};
use crate::qdrant::value::Kind;
use crate::qdrant::{ListValue, PointId, RetrievedPoint, ScoredPoint, Struct, Vectors};
static NULL_VALUE: Value = Value {
kind: Some(Kind::NullValue(0)),
};
impl PointStruct {
pub fn new(
id: impl Into<PointId>,
vectors: impl Into<Vectors>,
payload: impl Into<Payload>,
) -> Self {
Self {
id: Some(id.into()),
payload: payload.into().into(),
vectors: Some(vectors.into()),
}
}
}
impl RetrievedPoint {
pub fn get(&self, key: &str) -> &Value {
self.try_get(key).unwrap_or(&NULL_VALUE)
}
pub fn try_get(&self, key: &str) -> Option<&Value> {
self.payload.get(key)
}
}
impl ScoredPoint {
pub fn get(&self, key: &str) -> &Value {
self.try_get(key).unwrap_or(&NULL_VALUE)
}
pub fn try_get(&self, key: &str) -> Option<&Value> {
self.payload.get(key)
}
}
macro_rules! extract {
($kind:ident, $check:ident) => {
#[doc = stringify!([$kind])]
pub fn $check(&self) -> bool {
matches!(self.kind, Some($kind(_)))
}
};
($kind:ident, $check:ident, $extract:ident, $ty:ty) => {
extract!($kind, $check);
#[doc = stringify!([$ty])]
#[doc = stringify!([$kind].)]
pub fn $extract(&self) -> Option<$ty> {
if let Some($kind(v)) = self.kind {
Some(v)
} else {
None
}
}
};
($kind:ident, $check:ident, $extract:ident, ref $ty:ty) => {
extract!($kind, $check);
#[doc = stringify!([$ty])]
#[doc = stringify!([$kind].)]
pub fn $extract(&self) -> Option<&$ty> {
if let Some($kind(v)) = &self.kind {
Some(v)
} else {
None
}
}
};
}
mod value_extract_impl {
use crate::qdrant::value::Kind::*;
use crate::qdrant::{Struct, Value};
impl Value {
extract!(NullValue, is_null);
extract!(BoolValue, is_bool, as_bool, bool);
extract!(IntegerValue, is_integer, as_integer, i64);
extract!(DoubleValue, is_double, as_double, f64);
extract!(StringValue, is_str, as_str, ref String);
extract!(ListValue, is_list, as_list, ref [Value]);
extract!(StructValue, is_struct, as_struct, ref Struct);
}
}
impl Value {
#[cfg(feature = "serde")]
pub fn into_json(self) -> serde_json::Value {
use serde_json::Value as JsonValue;
match self.kind {
Some(Kind::BoolValue(b)) => JsonValue::Bool(b),
Some(Kind::IntegerValue(i)) => JsonValue::from(i),
Some(Kind::DoubleValue(d)) => JsonValue::from(d),
Some(Kind::StringValue(s)) => JsonValue::String(s),
Some(Kind::ListValue(vs)) => vs.into_iter().map(Value::into_json).collect(),
Some(Kind::StructValue(s)) => s
.fields
.into_iter()
.map(|(k, v)| (k, v.into_json()))
.collect(),
Some(Kind::NullValue(_)) | None => JsonValue::Null,
}
}
}
#[cfg(feature = "serde")]
impl From<Value> for serde_json::Value {
fn from(value: Value) -> Self {
value.into_json()
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.kind {
Some(Kind::BoolValue(b)) => write!(f, "{}", b),
Some(Kind::IntegerValue(i)) => write!(f, "{}", i),
Some(Kind::DoubleValue(v)) => write!(f, "{}", v),
Some(Kind::StringValue(s)) => write!(f, "{:?}", s),
Some(Kind::ListValue(vs)) => {
let mut i = vs.values.iter();
write!(f, "[")?;
if let Some(first) = i.next() {
write!(f, "{}", first)?;
for v in i {
write!(f, ",{}", v)?;
}
}
write!(f, "]")
}
Some(Kind::StructValue(s)) => {
let mut i = s.fields.iter();
write!(f, "{{")?;
if let Some((key, value)) = i.next() {
write!(f, "{:?}:{}", key, value)?;
for (key, value) in i {
write!(f, ",{:?}:{}", key, value)?;
}
}
write!(f, "}}")
}
_ => write!(f, "null"),
}
}
}
impl Value {
pub fn try_list_iter(&self) -> Option<impl Iterator<Item = &Value>> {
if let Some(Kind::ListValue(values)) = &self.kind {
Some(values.iter())
} else {
None
}
}
#[deprecated(since = "1.10.0", note = "use `try_list_iter` instead")]
#[allow(deprecated)]
pub fn iter_list(&self) -> Result<impl Iterator<Item = &Value>, NotA<ListValue>> {
if let Some(Kind::ListValue(values)) = &self.kind {
Ok(values.iter())
} else {
Err(NotA::default())
}
}
pub fn get_value(&self, key: &str) -> Option<&Value> {
if let Some(Kind::StructValue(Struct { fields })) = &self.kind {
Some(fields.get(key)?)
} else {
None
}
}
#[deprecated(since = "1.10.0", note = "use `get_value` instead")]
#[allow(deprecated)]
pub fn get_struct(&self, key: &str) -> Result<&Value, NotA<Struct>> {
if let Some(Kind::StructValue(Struct { fields })) = &self.kind {
Ok(fields.get(key).unwrap_or(&NULL_VALUE))
} else {
Err(NotA::default())
}
}
}
impl std::ops::Deref for ListValue {
type Target = [Value];
fn deref(&self) -> &[Value] {
&self.values
}
}
impl IntoIterator for ListValue {
type Item = Value;
type IntoIter = std::vec::IntoIter<Value>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl ListValue {
pub fn iter(&self) -> std::slice::Iter<'_, Value> {
self.values.iter()
}
}
impl Hash for PointId {
fn hash<H: Hasher>(&self, state: &mut H) {
use crate::qdrant::point_id::PointIdOptions::{Num, Uuid};
match &self.point_id_options {
Some(Num(u)) => state.write_u64(*u),
Some(Uuid(s)) => s.hash(state),
None => {}
}
}
}
impl Hash for ScoredPoint {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state)
}
}
impl Hash for RetrievedPoint {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state)
}
}