django_query/persian_rug/
sorting.rs

1use crate::sorting::{Field, SortVisitor, Sorter, SorterTypedClass};
2use crate::sorting::{Meta, SortableWithContext};
3
4use core::cmp::Ordering;
5
6use persian_rug::{Accessor, Proxy};
7
8#[persian_rug::constraints(context=C, access(T))]
9impl<'s, A, T, C> SortableWithContext<'s, A> for Proxy<T>
10where
11    T: SortableWithContext<'s, A>,
12    A: Accessor<Context = C> + 's,
13{
14    type Meta = ProxyMeta<A>;
15
16    fn get_meta(access: A) -> Self::Meta {
17        ProxyMeta { access }
18    }
19}
20
21pub struct ProxyMeta<A> {
22    access: A,
23}
24
25#[persian_rug::constraints(context = C, access(T))]
26impl<'s, A, C, T> Meta<'s, Proxy<T>> for ProxyMeta<A>
27where
28    A: Accessor<Context = C> + 's,
29    T: SortableWithContext<'s, A>,
30{
31    fn accept_visitor<V: SortVisitor<'s, Target = Proxy<T>>>(&self, visitor: &mut V)
32    where
33        Self: Sized,
34    {
35        let mut v = ProxyVisitor {
36            parent: visitor,
37            access: self.access.clone(),
38        };
39        T::get_meta(self.access.clone()).accept_visitor(&mut v);
40    }
41}
42
43struct ProxyVisitor<'a, P, A> {
44    parent: &'a mut P,
45    access: A,
46}
47
48#[persian_rug::constraints(context = C, access(R))]
49impl<'a, 's, A, C, P, R> SortVisitor<'s> for ProxyVisitor<'a, P, A>
50where
51    A: Accessor<Context = C> + 's,
52    P: SortVisitor<'s, Target = Proxy<R>>,
53{
54    type Target = R;
55    fn visit_sort<F, T, S>(&mut self, name: &str, field: &F, sort: &S)
56    where
57        F: Field<R, Value = T> + 's,
58        S: SorterTypedClass<T> + 's,
59        <S as SorterTypedClass<T>>::Sorter: 's,
60    {
61        self.parent.visit_sort(
62            name,
63            &ProxyField {
64                inner: field.clone(),
65                access: self.access.clone(),
66            },
67            sort,
68        );
69    }
70
71    fn visit_key_sort<F, T, M>(&mut self, name: &str, field: &F, sort_key: &str, meta: M)
72    where
73        F: Field<R, Value = T> + 's,
74        M: Meta<'s, T>,
75    {
76        self.parent.visit_key_sort(
77            name,
78            &ProxyField {
79                inner: field.clone(),
80                access: self.access.clone(),
81            },
82            sort_key,
83            meta,
84        );
85    }
86}
87
88#[derive(Clone)]
89struct ProxyField<F, A> {
90    inner: F,
91    access: A,
92}
93
94#[persian_rug::constraints(context=C, access(R))]
95impl<A, C, R, F, T> Field<Proxy<R>> for ProxyField<F, A>
96where
97    A: Accessor<Context = C>,
98    F: Field<R, Value = T>,
99{
100    type Value = T;
101    fn apply_sorter<V: Sorter<Self::Value>>(&self, op: &V, a: &Proxy<R>, b: &Proxy<R>) -> Ordering {
102        self.inner.apply_sorter(
103            &ProxyOp { parent: op },
104            self.access.get(a),
105            self.access.get(b),
106        )
107    }
108}
109
110struct ProxyOp<'a, V> {
111    parent: &'a V,
112}
113
114impl<'a, V, T> Sorter<T> for ProxyOp<'a, V>
115where
116    V: Sorter<T>,
117{
118    fn compare(&self, a: &T, b: &T) -> Ordering {
119        self.parent.compare(a, b)
120    }
121}
122
123pub use django_query_derive::SortableWithPersianRug;