use crate::errors::*;
use crate::row::*;
use crate::types::*;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::hash::Hash;
impl<A: TryFrom<BoltType, Error = Error>> TryFrom<BoltType> for Vec<A> {
type Error = Error;
fn try_from(input: BoltType) -> Result<Vec<A>> {
match input {
BoltType::List(l) => l.value.iter().map(|x| A::try_from(x.clone())).collect(),
_ => Err(Error::ConversionError),
}
}
}
impl<K, V> TryFrom<BoltType> for HashMap<K, V>
where
K: From<BoltString> + Eq + Hash,
V: TryFrom<BoltType, Error = Error>,
{
type Error = Error;
fn try_from(input: BoltType) -> Result<HashMap<K, V>> {
match input {
BoltType::Map(l) => l
.value
.into_iter()
.filter_map(|(k, v)| {
if let BoltType::Null(_) = v {
None
} else {
V::try_from(v).map(|v| Some((K::from(k), v))).transpose()
}
})
.collect::<Result<HashMap<_, _>>>(),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for f64 {
type Error = Error;
fn try_from(input: BoltType) -> Result<f64> {
match input {
BoltType::Float(t) => Ok(t.value),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for i64 {
type Error = Error;
fn try_from(input: BoltType) -> Result<i64> {
match input {
BoltType::Integer(t) => Ok(t.value),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for bool {
type Error = Error;
fn try_from(input: BoltType) -> Result<bool> {
match input {
BoltType::Boolean(t) => Ok(t.value),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Point2D {
type Error = Error;
fn try_from(input: BoltType) -> Result<Point2D> {
match input {
BoltType::Point2D(p) => Ok(Point2D::new(p)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for std::time::Duration {
type Error = Error;
fn try_from(input: BoltType) -> Result<std::time::Duration> {
match input {
BoltType::Duration(d) => Ok(d.into()),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for chrono::NaiveDate {
type Error = Error;
fn try_from(input: BoltType) -> Result<chrono::NaiveDate> {
match input {
BoltType::Date(d) => d.try_into(),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for chrono::DateTime<chrono::FixedOffset> {
type Error = Error;
fn try_from(input: BoltType) -> Result<chrono::DateTime<chrono::FixedOffset>> {
match input {
BoltType::DateTime(d) => d.try_into(),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for chrono::NaiveDateTime {
type Error = Error;
fn try_from(input: BoltType) -> Result<chrono::NaiveDateTime> {
match input {
BoltType::LocalDateTime(d) => d.try_into(),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for (chrono::NaiveTime, Option<chrono::FixedOffset>) {
type Error = Error;
fn try_from(input: BoltType) -> Result<(chrono::NaiveTime, Option<chrono::FixedOffset>)> {
match input {
BoltType::Time(bolt_time) => {
let (time, offset) = bolt_time.into();
if offset.local_minus_utc() == 0 {
Ok((time, None))
} else {
Ok((time, Some(offset)))
}
}
BoltType::LocalTime(d) => Ok((d.into(), None)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for (chrono::NaiveDateTime, String) {
type Error = Error;
fn try_from(input: BoltType) -> Result<(chrono::NaiveDateTime, String)> {
match input {
BoltType::DateTimeZoneId(date_time_zone_id) => date_time_zone_id.try_into(),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Vec<u8> {
type Error = Error;
fn try_from(input: BoltType) -> Result<Vec<u8>> {
match input {
BoltType::Bytes(b) => Ok(b.value.to_vec()),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Point3D {
type Error = Error;
fn try_from(input: BoltType) -> Result<Point3D> {
match input {
BoltType::Point3D(p) => Ok(Point3D::new(p)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Node {
type Error = Error;
fn try_from(input: BoltType) -> Result<Node> {
match input {
BoltType::Node(n) => Ok(Node::new(n)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Path {
type Error = Error;
fn try_from(input: BoltType) -> Result<Path> {
match input {
BoltType::Path(n) => Ok(Path::new(n)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for Relation {
type Error = Error;
fn try_from(input: BoltType) -> Result<Relation> {
match input {
BoltType::Relation(r) => Ok(Relation::new(r)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for UnboundedRelation {
type Error = Error;
fn try_from(input: BoltType) -> Result<UnboundedRelation> {
match input {
BoltType::UnboundedRelation(r) => Ok(UnboundedRelation::new(r)),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for BoltList {
type Error = Error;
fn try_from(input: BoltType) -> Result<BoltList> {
match input {
BoltType::List(l) => Ok(l),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for BoltString {
type Error = Error;
fn try_from(input: BoltType) -> Result<BoltString> {
match input {
BoltType::String(s) => Ok(s),
_ => Err(Error::ConversionError),
}
}
}
impl TryFrom<BoltType> for String {
type Error = Error;
fn try_from(input: BoltType) -> Result<String> {
match input {
BoltType::String(t) => Ok(t.value),
_ => Err(Error::ConversionError),
}
}
}
impl From<std::time::Duration> for BoltType {
fn from(value: std::time::Duration) -> BoltType {
BoltType::Duration(value.into())
}
}
impl From<chrono::NaiveDate> for BoltType {
fn from(value: chrono::NaiveDate) -> BoltType {
BoltType::Date(value.into())
}
}
impl From<chrono::NaiveTime> for BoltType {
fn from(value: chrono::NaiveTime) -> BoltType {
BoltType::LocalTime(value.into())
}
}
impl From<chrono::NaiveDateTime> for BoltType {
fn from(value: chrono::NaiveDateTime) -> BoltType {
BoltType::LocalDateTime(value.into())
}
}
impl From<chrono::DateTime<chrono::FixedOffset>> for BoltType {
fn from(value: chrono::DateTime<chrono::FixedOffset>) -> Self {
BoltType::DateTime(value.into())
}
}
impl From<(chrono::NaiveTime, chrono::FixedOffset)> for BoltType {
fn from(value: (chrono::NaiveTime, chrono::FixedOffset)) -> Self {
BoltType::Time(value.into())
}
}
impl From<(chrono::NaiveDateTime, &str)> for BoltType {
fn from(value: (chrono::NaiveDateTime, &str)) -> Self {
BoltType::DateTimeZoneId(value.into())
}
}
impl<A: Into<BoltType> + Clone> From<Vec<A>> for BoltType {
fn from(value: Vec<A>) -> BoltType {
BoltType::List(BoltList {
value: value.iter().map(|v| v.clone().into()).collect(),
})
}
}
impl<A: Into<BoltType> + Clone> From<&[A]> for BoltType {
fn from(value: &[A]) -> Self {
BoltType::List(BoltList {
value: value.iter().map(|v| v.clone().into()).collect(),
})
}
}
impl<K, V> From<HashMap<K, V>> for BoltType
where
K: Into<BoltString>,
V: Into<BoltType>,
{
fn from(value: HashMap<K, V>) -> Self {
BoltType::Map(
value
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
)
}
}
impl From<Vec<u8>> for BoltType {
fn from(value: Vec<u8>) -> Self {
BoltType::Bytes(BoltBytes::new(value.into()))
}
}
impl From<&[u8]> for BoltType {
fn from(value: &[u8]) -> Self {
Self::from(value.to_vec())
}
}
impl From<f64> for BoltType {
fn from(val: f64) -> Self {
BoltType::Float(BoltFloat::new(val))
}
}
impl From<f32> for BoltType {
fn from(val: f32) -> Self {
Self::from(f64::from(val))
}
}
impl From<bool> for BoltType {
fn from(val: bool) -> Self {
BoltType::Boolean(BoltBoolean::new(val))
}
}
impl From<i64> for BoltType {
fn from(value: i64) -> BoltType {
BoltType::Integer(BoltInteger::new(value))
}
}
macro_rules! int_impl {
($($ty:ty),+) => {
$(
impl From<$ty> for BoltType {
fn from(val: $ty) -> Self {
Self::from(i64::from(val))
}
}
)+
};
(try $($ty:ty),+) => {
$(
impl TryFrom<$ty> for BoltType {
type Error = ::std::num::TryFromIntError;
fn try_from(val: $ty) -> ::std::result::Result<Self, Self::Error> {
match i64::try_from(val) {
Ok(v) => Ok(Self::from(v)),
Err(e) => Err(e),
}
}
}
)+
};
}
int_impl!(i8, i16, i32, u16, u32);
int_impl!(try isize, i128, usize, u64, u128);
impl From<String> for BoltType {
fn from(value: String) -> Self {
BoltType::String(value.into())
}
}
impl From<&str> for BoltType {
fn from(value: &str) -> Self {
BoltType::String(value.into())
}
}
impl<T: Into<BoltType>> From<Option<T>> for BoltType {
fn from(value: Option<T>) -> Self {
match value {
Some(v) => v.into(),
None => BoltType::Null(BoltNull),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn convert_into_vec() {
let value = BoltType::List(BoltList {
value: vec![
BoltType::Integer(BoltInteger::new(42)),
BoltType::Integer(BoltInteger::new(1337)),
],
});
let value = Vec::<i64>::try_from(value).unwrap();
assert_eq!(value, vec![42, 1337]);
}
#[test]
fn convert_into_map() {
let map = HashMap::from([
(BoltString::new("42"), BoltType::Null(BoltNull {})),
(
BoltString::new("1337"),
BoltType::Integer(BoltInteger::new(1337)),
),
]);
let value = BoltType::Map(BoltMap { value: map });
let value = HashMap::<String, i64>::try_from(value).unwrap();
assert_eq!(value, HashMap::from([("1337".to_owned(), 1337_i64)]));
}
#[test]
fn convert_propagates_error() {
let value = BoltType::List(BoltList {
value: vec![
BoltType::Integer(BoltInteger::new(42)),
BoltType::Float(BoltFloat::new(13.37)),
],
});
let value = Vec::<i64>::try_from(value).unwrap_err();
assert!(matches!(value, Error::ConversionError));
}
#[test]
fn convert_from_vec() {
let value: Vec<i64> = vec![42, 1337];
let value: BoltType = value.into();
assert_eq!(
value,
BoltType::List(BoltList {
value: vec![
BoltType::Integer(BoltInteger::new(42)),
BoltType::Integer(BoltInteger::new(1337)),
],
})
);
}
#[test]
fn convert_from_map() {
let map = HashMap::from([("1337".to_owned(), 1337_i64)]);
let value: BoltType = map.into();
assert_eq!(
value,
BoltType::Map(BoltMap {
value: HashMap::from([(
BoltString::new("1337"),
BoltType::Integer(BoltInteger::new(1337))
)]),
})
);
}
#[test]
fn convert_from_slice() {
let value: Vec<i64> = vec![42, 1337];
let value: BoltType = value.as_slice().into();
assert_eq!(
value,
BoltType::List(BoltList {
value: vec![
BoltType::Integer(BoltInteger::new(42)),
BoltType::Integer(BoltInteger::new(1337)),
],
})
);
}
#[test]
fn convert_from_option() {
let value: Option<Vec<i64>> = Some(vec![42, 1337]);
let value: BoltType = value.into();
assert_eq!(
value,
BoltType::List(BoltList {
value: vec![
BoltType::Integer(BoltInteger::new(42)),
BoltType::Integer(BoltInteger::new(1337)),
],
})
);
let value: Option<Vec<i64>> = None;
let value: BoltType = value.into();
assert_eq!(value, BoltType::Null(BoltNull));
}
}