// This code is automatically generated by Senax and is always overwritten.

use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use rust_decimal::Decimal;
use senax_common::{cache::calc_mem_size, ShardId};
use serde_json::Value;
use sqlx::query::Query;
use std::convert::TryFrom;

use crate::connection::{DbArguments, DbType};

macro_rules! fetch {
    ( $conn:ident, $query:ident, $method:ident ) => {
        if $conn.has_read_tx() {
            $query.$method($conn.get_read_tx().await?.as_mut()).await?
@%- if !config.force_disable_cache %@
        } else if $conn.has_cache_tx() {
            $query.$method($conn.get_cache_tx().await?.as_mut()).await?
@%- endif %@
        } else if $conn.has_tx() {
            $query.$method($conn.get_tx().await?.as_mut()).await?
        } else {
            $query.$method($conn.get_reader().await?.as_mut()).await?
        }
    };
}
pub(crate) use fetch;

#[derive(Default, sqlx::FromRow, senax_macros::SqlCol)]
pub struct Count {
    #[sql(query = "count(*)")]
    pub c: i64,
}

#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub(crate) enum TrashMode {
    #[default]
    Not,
    With,
    Only,
}

pub(crate) trait ColTr {
    fn name(&self) -> &'static str;
}
pub(crate) trait BindTr {
    fn name(&self) -> &'static str;
    fn placeholder(&self) -> &'static str {
        ""
    }
    fn len(&self) -> usize {
        1
    }
    fn bind_to_query(self, query: Query<'_, DbType, DbArguments>)
        -> Query<'_, DbType, DbArguments>;
}
#[allow(dead_code)]
pub(crate) trait BindArrayTr {
    fn query_each_bind(
        self,
        query: Query<'_, DbType, DbArguments>,
    ) -> Query<'_, DbType, DbArguments>;
}
pub(crate) trait ColRelTr {
    fn write_rel(&self, buf: &mut String, idx: usize, without_key: bool, shard_id: ShardId, is_outer: bool);
    fn write_key(&self, buf: &mut String);
    fn bind_to_query(self, query: Query<'_, DbType, DbArguments>)
        -> Query<'_, DbType, DbArguments>;
}
pub(crate) trait FilterTr
where
    Self: Sized,
{
    fn write(&self, buf: &mut String, idx: usize, trash_mode: &mut TrashMode, shard_id: ShardId, is_outer: bool);
    fn bind_to_query(
        self,
        query: sqlx::query::Query<'_, DbType, DbArguments>,
    ) -> sqlx::query::Query<'_, DbType, DbArguments>;
    fn write_where(
        filter: &Option<Self>,
        trash_mode: TrashMode,
        trashed_sql: &str,
        not_trashed_sql: &str,
        only_trashed_sql: &str,
        shard_id: ShardId,
    ) -> String;
}
pub(crate) trait OrderTr
where
    Self: Sized,
{
    fn write(&self, buf: &mut String);
    fn write_order(order: &Option<Vec<Self>>, raw_order: &Option<String>) -> String;
}

#[rustfmt::skip]
macro_rules! filter {
    ( $t:ty ) => {
        fn write(&self, buf: &mut String, idx: usize, trash_mode: &mut TrashMode, shard_id: ShardId, is_outer: bool) {
            match self {
                Filter_::WithTrashed => {
                    *trash_mode = TrashMode::With;
                }
                Filter_::OnlyTrashed => {
                    *trash_mode = TrashMode::Only;
                }
                Filter_::Match(cols, _v) => {
                    buf.push_str(" MATCH (");
                    for c in cols {
                        buf.push_str(c.name());
                        buf.push_str(",");
                    }
                    buf.truncate(buf.len() - 1);
                    buf.push_str(") AGAINST (?) AND ");
                }
                Filter_::MatchBoolean(cols, _v) => {
                    buf.push_str(" MATCH (");
                    for c in cols {
                        buf.push_str(c.name());
                        buf.push_str(",");
                    }
                    buf.truncate(buf.len() - 1);
                    buf.push_str(") AGAINST (?  IN BOOLEAN MODE) AND ");
                }
                Filter_::MatchExpansion(cols, _v) => {
                    buf.push_str(" MATCH (");
                    for c in cols {
                        buf.push_str(c.name());
                        buf.push_str(",");
                    }
                    buf.truncate(buf.len() - 1);
                    buf.push_str(") AGAINST (?  WITH QUERY EXPANSION) AND ");
                }
                Filter_::IsNull(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" IS NULL AND ");
                }
                Filter_::IsNotNull(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" IS NOT NULL AND ");
                }
                Filter_::Eq(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" = ");
                    buf.push_str(c.placeholder());
                    buf.push_str(" AND ");
                }
                Filter_::EqKey(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" = ? AND ");
                }
                Filter_::NotEq(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" != ? AND ");
                }
                Filter_::Gt(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" > ");
                    buf.push_str(c.placeholder());
                    buf.push_str(" AND ");
                }
                Filter_::Gte(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" >= ");
                    buf.push_str(c.placeholder());
                    buf.push_str(" AND ");
                }
                Filter_::Lt(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" < ");
                    buf.push_str(c.placeholder());
                    buf.push_str(" AND ");
                }
                Filter_::Lte(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" <= ");
                    buf.push_str(c.placeholder());
                    buf.push_str(" AND ");
                }
                Filter_::Like(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" LIKE ? AND ");
                }
                Filter_::AllBits(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" & ? = ? AND ");
                }
                Filter_::AnyBits(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" & ? != 0 AND ");
                }
                Filter_::In(c) => {
                    if c.len() > 0 {
                        buf.push_str(c.name());
                        buf.push_str(" IN (");
                        for _i in 0..c.len() {
                            buf.push_str(c.placeholder());
                            buf.push_str(",");
                        }
                        buf.truncate(buf.len() - 1);
                        buf.push_str(") AND ");
                    } else {
                        buf.push_str("false AND ");
                    }
                }
                Filter_::NotIn(c) => {
                    if c.len() > 0 {
                        buf.push_str(c.name());
                        buf.push_str(" NOT IN (");
                        for _i in 0..c.len() {
                            buf.push_str(c.placeholder());
                            buf.push_str(",");
                        }
                        buf.truncate(buf.len() - 1);
                        buf.push_str(") AND ");
                    }
                }
                Filter_::MemberOf(c, p) => {
                    buf.push_str("CAST(? AS JSON) MEMBER OF (");
                    if p.is_some() {
                        buf.push_str("JSON_EXTRACT(");
                        buf.push_str(c.name());
                        buf.push_str(", ?)");
                    } else {
                        buf.push_str(c.name());
                    }
                    buf.push_str(") AND ");
                }
                Filter_::Contains(c, p) => {
                    buf.push_str("JSON_CONTAINS(");
                    if p.is_some() {
                        buf.push_str("JSON_EXTRACT(");
                        buf.push_str(c.name());
                        buf.push_str(", ?)");
                    } else {
                        buf.push_str(c.name());
                    }
                    buf.push_str(", CAST(? AS JSON)) AND ");
                }
                Filter_::Overlaps(c, p) => {
                    buf.push_str("JSON_OVERLAPS(");
                    if p.is_some() {
                        buf.push_str("JSON_EXTRACT(");
                        buf.push_str(c.name());
                        buf.push_str(", ?)");
                    } else {
                        buf.push_str(c.name());
                    }
                    buf.push_str(", CAST(? AS JSON)) AND ");
                }
                Filter_::JsonIn(c, p) => {
                    buf.push_str("JSON_OVERLAPS(JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?)");
                    buf.push_str(", CAST(? AS JSON)) AND ");
                }
                Filter_::JsonContainsPath(c, _p) => {
                    buf.push_str("JSON_CONTAINS_PATH(");
                    buf.push_str(c.name());
                    buf.push_str(", 'one', ?) AND ");
                }
                Filter_::JsonEq(c, _p) => {
                    buf.push_str("JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?) = CAST(? AS JSON) AND ");
                }
                Filter_::JsonLt(c, _p) => {
                    buf.push_str("JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?) < CAST(? AS JSON) AND ");
                }
                Filter_::JsonLte(c, _p) => {
                    buf.push_str("JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?) <= CAST(? AS JSON) AND ");
                }
                Filter_::JsonGt(c, _p) => {
                    buf.push_str("JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?) > CAST(? AS JSON) AND ");
                }
                Filter_::JsonGte(c, _p) => {
                    buf.push_str("JSON_EXTRACT(");
                    buf.push_str(c.name());
                    buf.push_str(", ?) >= CAST(? AS JSON) AND ");
                }
                Filter_::Within(c) => {
                    buf.push_str("ST_Within(");
                    buf.push_str(c.name());
                    buf.push_str(", ST_GeomFromGeoJSON(?, 2, ?)) AND ");
                }
                Filter_::Intersects(c) => {
                    buf.push_str("ST_Intersects(");
                    buf.push_str(c.name());
                    buf.push_str(", ST_GeomFromGeoJSON(?, 2, ?)) AND ");
                }
                Filter_::Crosses(c) => {
                    buf.push_str("ST_Crosses(");
                    buf.push_str(c.name());
                    buf.push_str(", ST_GeomFromGeoJSON(?, 2, ?)) AND ");
                }
                Filter_::DWithin(c) => {
                    buf.push_str("ST_Distance(");
                    buf.push_str(c.name());
                    buf.push_str(", ST_GeomFromGeoJSON(?, 2, ?)) <= ? AND ");
                    buf.push_str("ST_Intersects(");
                    buf.push_str(c.name());
                    buf.push_str(", ST_Buffer(ST_GeomFromGeoJSON(?, 2, ?), ? * 1.1)) AND ");
                }
                Filter_::Not(c) => {
                    buf.push_str("NOT (");
                    c.write(buf, idx, trash_mode, shard_id, is_outer);
                    buf.truncate(buf.len() - 5);
                    buf.push_str(") AND ");
                }
                Filter_::And(v) => {
                    if !v.is_empty() {
                        buf.push_str("(");
                        for c in v.iter() {
                            c.write(buf, idx, trash_mode, shard_id, is_outer);
                        }
                        buf.truncate(buf.len() - 5);
                        buf.push_str(") AND ");
                    } else {
                        buf.push_str("true AND ");
                    }
                }
                Filter_::Or(v) => {
                    if !v.is_empty() {
                        buf.push_str("(");
                        for c in v.iter() {
                            c.write(buf, idx, trash_mode, shard_id, is_outer);
                            buf.truncate(buf.len() - 5);
                            buf.push_str(" OR ");
                        }
                        buf.truncate(buf.len() - 4);
                        buf.push_str(") AND ");
                    } else {
                        buf.push_str("false AND ");
                    }
                }
                Filter_::Exists(c) => {
                    buf.push_str("EXISTS (");
                    c.write_rel(buf, idx, false, shard_id, is_outer);
                    buf.push_str(") AND ");
                }
                Filter_::NotExists(c) => {
                    buf.push_str("NOT EXISTS (");
                    c.write_rel(buf, idx, false, shard_id, is_outer);
                    buf.push_str(") AND ");
                }
                Filter_::EqAny(c) => {
                    c.write_key(buf);
                    buf.push_str(" = ANY (");
                    c.write_rel(buf, idx, true, shard_id, is_outer);
                    buf.push_str(") AND ");
                }
                Filter_::NotAll(c) => {
                    c.write_key(buf);
                    buf.push_str(" <> ALL (");
                    c.write_rel(buf, idx, true, shard_id, is_outer);
                    buf.push_str(") AND ");
                }
                Filter_::Raw(raw) => {
                    buf.push_str("(");
                    buf.push_str(raw@%- for db in config.outer_db() %@.replace("##@{ db }@##.", ::db_@{ db }@::connection::DbConn::real_db_name(shard_id)).as_str()@%- endfor %@);
                    buf.push_str(") AND ");
                }
                Filter_::RawWithParam(raw, _param) => {
                    buf.push_str("(");
                    buf.push_str(raw);
                    buf.push_str(") AND ");
                }
                Filter_::Boolean(_) => {
                    buf.push_str("? AND ");
                }
            };
        }
        fn bind_to_query(
            self,
            mut query: sqlx::query::Query<'_, DbType, DbArguments>,
        ) -> sqlx::query::Query<'_, DbType, DbArguments> {
            match self {
                Filter_::WithTrashed => query,
                Filter_::OnlyTrashed => query,
                Filter_::Match(_c, v) => query.bind(v),
                Filter_::MatchBoolean(_c, v) => query.bind(v),
                Filter_::MatchExpansion(_c, v) => query.bind(v),
                Filter_::IsNull(_c) => query,
                Filter_::IsNotNull(_c) => query,
                Filter_::Eq(c) => c.bind_to_query(query),
                Filter_::EqKey(c) => c.bind_to_query(query),
                Filter_::NotEq(c) => c.bind_to_query(query),
                Filter_::Gt(c) => c.bind_to_query(query),
                Filter_::Gte(c) => c.bind_to_query(query),
                Filter_::Lt(c) => c.bind_to_query(query),
                Filter_::Lte(c) => c.bind_to_query(query),
                Filter_::Like(c) => c.bind_to_query(query),
                Filter_::AllBits(c) => c.bind_to_query(query),
                Filter_::AnyBits(c) => c.bind_to_query(query),
                Filter_::In(c) => c.bind_to_query(query),
                Filter_::NotIn(c) => c.bind_to_query(query),
                Filter_::MemberOf(c, p) => if let Some(p) = p { c.bind_to_query(query).bind(p) } else { c.bind_to_query(query) },
                Filter_::Contains(c, p) => if let Some(p) = p { c.bind_to_query(query.bind(p)) } else { c.bind_to_query(query) },
                Filter_::Overlaps(c, p) => if let Some(p) = p { c.bind_to_query(query.bind(p)) } else { c.bind_to_query(query) },
                Filter_::JsonIn(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::JsonContainsPath(c, p) => query.bind(p),
                Filter_::JsonEq(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::JsonLt(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::JsonLte(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::JsonGt(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::JsonGte(c, p) => c.bind_to_query(query.bind(p)),
                Filter_::Within(c) => c.bind_to_query(query),
                Filter_::Intersects(c) => c.bind_to_query(query),
                Filter_::Crosses(c) => c.bind_to_query(query),
                Filter_::DWithin(c) => c.bind_to_query(query),
                Filter_::Not(c) => c.bind_to_query(query),
                Filter_::And(v) => {for c in v { query = c.bind_to_query(query); } query},
                Filter_::Or(v) => {for c in v { query = c.bind_to_query(query); } query},
                Filter_::Exists(c) => c.bind_to_query(query),
                Filter_::NotExists(c) => c.bind_to_query(query),
                Filter_::EqAny(c) => c.bind_to_query(query),
                Filter_::NotAll(c) => c.bind_to_query(query),
                Filter_::Raw(_c) => query,
                Filter_::RawWithParam(_c, param) => {for v in param { query = query.bind(v); } query},
                Filter_::Boolean(v) => query.bind(v),
            }
        }
        fn write_where(
            filter: &Option<Filter_>,
            mut trash_mode: TrashMode,
            trashed_sql: &str,
            not_trashed_sql: &str,
            only_trashed_sql: &str,
            shard_id: ShardId,
        ) -> String {
            let mut s = String::with_capacity(100);
            s.push_str("WHERE ");
            if let Some(ref c) = filter {
                c.write(&mut s, 1, &mut trash_mode, shard_id, false);
            }
            if trash_mode == TrashMode::Not {
                s.push_str(not_trashed_sql)
            } else if trash_mode == TrashMode::Only {
                s.push_str(only_trashed_sql)
            } else {
                s.push_str(trashed_sql)
            }
            if s.len() > "WHERE ".len() {
                s.truncate(s.len() - " AND ".len());
            } else {
                s.truncate(0);
            }
            s
        }
    };
}
pub(crate) use filter;

macro_rules! order {
    () => {
        fn write(&self, buf: &mut String) {
            match self {
                Order_::Asc(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" ASC, ");
                }
                Order_::Desc(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" DESC, ");
                }
                Order_::IsNullAsc(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" IS NULL ASC, ");
                }
                Order_::IsNullDesc(c) => {
                    buf.push_str(c.name());
                    buf.push_str(" IS NULL DESC, ");
                }
            };
        }
        fn write_order(order: &Option<Vec<Order_>>, raw_order: &Option<String>) -> String {
            if let Some(raw_order) = raw_order {
                return format!("ORDER BY {}", raw_order);
            }
            match order {
                Some(ref v) if !v.is_empty() => {
                    let mut s = String::with_capacity(100);
                    s.push_str("ORDER BY ");
                    for o in v {
                        o.write(&mut s);
                    }
                    s.truncate(s.len() - 2);
                    s
                }
                _ => String::new(),
            }
        }
    };
}
pub(crate) use order;

pub(crate) trait IntoJson<T> {
    fn _into_json(&self) -> String;
}

impl<T> IntoJson<T> for T
where
    T: serde::Serialize,
{
    fn _into_json(&self) -> String {
        let s = serde_json::to_string(self).unwrap();
        assert!(s.len() <= @{ config.max_db_str_len() }@, "Incorrect JSON length.");
        s
    }
}

pub(crate) trait Size {
    fn _size(&self) -> usize;
}

impl Size for String {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity()) + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u8> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity()) + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u32> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<u32>())
            + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u64> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<u64>())
            + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<String> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<usize>())
            + std::mem::size_of::<usize>() * 2
            + self.iter().fold(0, |i, v| {
                i + v.capacity() + std::mem::size_of::<usize>() * 2
            })
    }
}

pub trait Updater {
    fn is_new(&self) -> bool;
    fn has_been_deleted(&self) -> bool;
    fn mark_for_delete(&mut self);
    fn unmark_for_delete(&mut self);
    fn will_be_deleted(&self) -> bool;
    fn mark_for_upsert(&mut self);
    fn is_updated(&self) -> bool;
    fn overwrite_except_skip(&mut self, updater: Self);
    fn overwrite_only_set(&mut self, updater: Self);
    fn overwrite_with(&mut self, updater: Self, set_only: bool);
}

#[derive(Clone, Debug)]
pub enum BindValue {
    Bool(Option<bool>),
    Enum(Option<i64>),
    Number(Option<Decimal>),
    String(Option<String>),
    DateTime(Option<NaiveDateTime>),
    Date(Option<NaiveDate>),
    Time(Option<NaiveTime>),
    Blob(Option<Vec<u8>>),
    Json(Option<Value>),
    Uuid(Option<uuid::fmt::Hyphenated>),
    BinaryUuid(Option<uuid::Uuid>),
}

macro_rules! impl_bind_value {
    ($T:ty, $U:ident) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::$U(Some(t.into()))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::$U(t.map(|v| v.into()))
            }
        }
    };
}
impl_bind_value!(bool, Bool);
impl_bind_value!(String, String);
impl_bind_value!(NaiveDateTime, DateTime);
impl_bind_value!(NaiveDate, Date);
impl_bind_value!(NaiveTime, Time);
impl_bind_value!(Vec<u8>, Blob);
impl_bind_value!(Value, Json);
impl_bind_value!(uuid::Uuid, Uuid);

macro_rules! impl_decimal {
    ($T:ty) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::Number(Some(Decimal::from(t)))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::Number(t.map(|v| Decimal::from(v)))
            }
        }
    };
}

macro_rules! impl_try_decimal {
    ($T:ty) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::Number(Some(Decimal::try_from(t).unwrap()))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::Number(t.map(|v| Decimal::try_from(v).unwrap()))
            }
        }
    };
}

impl_decimal!(isize);
impl_decimal!(i8);
impl_decimal!(i16);
impl_decimal!(i32);
impl_decimal!(i64);
impl_decimal!(usize);
impl_decimal!(u8);
impl_decimal!(u16);
impl_decimal!(u32);
impl_decimal!(u64);
impl_decimal!(i128);
impl_decimal!(u128);
impl_decimal!(Decimal);
impl_try_decimal!(f32);
impl_try_decimal!(f64);

pub mod arc_bytes {
    use serde::{Deserialize, Deserializer, Serializer};
    use serde_bytes::ByteBuf;
    use std::sync::Arc;

    pub fn serialize<S>(data: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(data.as_slice())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let buf = ByteBuf::deserialize(deserializer)?;
        Ok(Arc::new(buf.into_vec()))
    }
}
pub mod option_arc_bytes {
    use serde::{Deserialize, Deserializer, Serializer};
    use serde_bytes::ByteBuf;
    use std::sync::Arc;

    pub fn serialize<S>(data: &Option<Arc<Vec<u8>>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match data {
            Some(value) => serializer.serialize_bytes(value.as_slice()),
            None => serializer.serialize_none(),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Arc<Vec<u8>>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        match Option::<ByteBuf>::deserialize(deserializer)? {
            Some(buf) => Ok(Some(Arc::new(buf.into_vec()))),
            None => Ok(None),
        }
    }
}

#[derive(serde::Deserialize, serde::Serialize, Clone, Default)]
pub(crate) struct JsonRawValue(std::sync::Arc<Box<serde_json::value::RawValue>>);
impl TryFrom<String> for JsonRawValue {
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn try_from(value: String) -> Result<Self, Self::Error> {
        Ok(Self(serde_json::value::RawValue::from_string(value)?.into()))
    }
}
impl PartialEq for JsonRawValue {
    fn eq(&self, other: &Self) -> bool {
        self.0.get() == other.0.get()
    }
}
impl From<&JsonRawValue> for String {
    fn from(value: &JsonRawValue) -> Self {
        value.0.get().to_string()
    }
}
impl Size for JsonRawValue {
    fn _size(&self) -> usize {
        calc_mem_size(self.0.get().len()) + std::mem::size_of::<usize>() * 4
    }
}
impl std::fmt::Debug for JsonRawValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", &self._into_json())
    }
}
impl JsonRawValue {
    pub fn _into_json(&self) -> String {
        let s: String = self.into();
        assert!(s.len() <= 4294967295, "Incorrect JSON length.");
        s
    }
    pub fn _to_value(&self) -> std::sync::Arc<Box<serde_json::value::RawValue>> {
        std::sync::Arc::clone(&self.0)
    }
}
pub(crate) trait ToJsonRawValue {
    fn _to_json_raw_value(&self) -> anyhow::Result<JsonRawValue>;
}

impl<T> ToJsonRawValue for T
where
    T: serde::Serialize,
{
    fn _to_json_raw_value(&self) -> anyhow::Result<JsonRawValue> {
        let v = serde_json::to_string(self)?;
        Ok(JsonRawValue(serde_json::value::RawValue::from_string(v)?.into()))
    }
}
@{-"\n"}@