1use core::ops::ControlFlow;
2
3use crate::{
4 body::admit::{Finished, Open, Track},
5 decode::{
6 exec, request,
7 state::{
8 Admission, Admitted, Each, Finish, Flow, Fold, Map, Set, Slot, Uniforms, Whole, admit,
9 body, open,
10 },
11 },
12};
13
14pub struct Uniform<P, F: Set> {
16 slot: Whole<P>,
17 body: request::Body<F::SyncOpen, F::SyncFinished>,
18}
19
20impl<P, F: Set> Uniform<P, F> {
21 pub const fn new(prep: P, body: request::Body<F::SyncOpen, F::SyncFinished>) -> Self {
22 Self {
23 slot: Whole::new(prep),
24 body,
25 }
26 }
27
28 pub(super) fn into_parts(self) -> (P, request::Body<F::SyncOpen, F::SyncFinished>) {
29 (self.slot.0, self.body)
30 }
31}
32
33impl<P> Uniform<P, Admitted> {
34 pub fn into_request(self) -> AdmittedBody<P> {
35 match self.body {
36 request::Body::Open(body) => request::Body::Open(self.slot.admit(body)),
37 request::Body::Finished(body) => request::Body::Finished(self.slot.admit(body)),
38 }
39 }
40}
41
42impl<P, F: Set> Flow<P, F> for Uniform<P, F> {
43 type Family = Uniforms<P>;
44
45 fn each<'a, M: Each<P, F>>(&'a mut self, each: M) -> M::Output<'a> {
46 match &mut self.body {
47 request::Body::Open(body) => each.sync_open(&self.slot, body),
48 request::Body::Finished(body) => each.sync_done(&self.slot, body),
49 }
50 }
51
52 fn map_retain<G: Set, M: Map<P, F, G>>(
53 self,
54 map: M,
55 ) -> ControlFlow<M::Break, (M::Retained, Uniform<P, G>)> {
56 let (retained, slot, body) = match self.body {
57 request::Body::Open(body) => {
58 let (retained, slot, body) = map.sync_open(self.slot, body)?;
59 (retained, slot, request::Body::Open(body))
60 }
61 request::Body::Finished(body) => {
62 let (retained, slot, body) = map.sync_done(self.slot, body)?;
63 (retained, slot, request::Body::Finished(body))
64 }
65 };
66 ControlFlow::Continue((retained, Uniform { slot, body }))
67 }
68
69 fn fold<T: Fold<P, F>>(self, fold: T) -> T::Output {
70 match self.body {
71 request::Body::Open(body) => fold.sync_open(self.slot, body),
72 request::Body::Finished(body) => fold.sync_done(self.slot, body),
73 }
74 }
75
76 fn finish(self) -> Result<Self, Self>
77 where
78 F: Finish,
79 {
80 let request::Body::Open(body) = self.body else {
81 return Err(self);
82 };
83 Ok(Self {
84 slot: self.slot,
85 body: request::Body::Finished(F::sync(body)),
86 })
87 }
88
89 fn each_open<'a, V: open::Each<F>>(&'a mut self, visit: V) -> V::Output<'a>
90 where
91 F: open::Set,
92 {
93 match &mut self.body {
94 request::Body::Open(body) => visit.apply(body),
95 request::Body::Finished(never) => match *never {},
96 }
97 }
98
99 fn fold_open<V: open::Fold<P, F>>(self, visit: V) -> V::Output
100 where
101 F: open::Set,
102 {
103 match self.body {
104 request::Body::Open(body) => visit.sync(self.slot, body),
105 request::Body::Finished(never) => match never {},
106 }
107 }
108
109 fn consume<O, V: FnOnce(F::Body) -> O>(self, visit: V) -> O
110 where
111 F: open::Set,
112 {
113 match self.body {
114 request::Body::Open(body) => visit(body),
115 request::Body::Finished(never) => match never {},
116 }
117 }
118}
119
120impl<P, F: Set> body::Flow<F> for Uniform<P, F> {
121 fn fold<T: body::Fold<F>>(self, fold: T) -> T::Output {
122 match self.body {
123 request::Body::Open(body) => fold.apply(body::Value::SyncOpen(body)),
124 request::Body::Finished(body) => fold.apply(body::Value::SyncFinished(body)),
125 }
126 }
127}
128
129impl<P, F, G> Admission<P, F, G> for Uniform<P, F>
130where
131 F: Set,
132 G: Set,
133{
134 type Output = Uniform<P, G>;
135
136 fn admit<V: admit::Visit<P, F, G>>(self, visit: &mut V) -> ControlFlow<V::Break, Self::Output> {
137 let (slot, body) = match self.body {
138 request::Body::Open(body) => {
139 let (slot, body) = visit.sync_open(self.slot, body)?;
140 (slot, request::Body::Open(body))
141 }
142 request::Body::Finished(body) => {
143 let (slot, body) = visit.sync_done(self.slot, body)?;
144 (slot, request::Body::Finished(body))
145 }
146 };
147 ControlFlow::Continue(Uniform { slot, body })
148 }
149}
150
151type AdmittedBody<P> = request::Body<
152 request::Admitted<exec::Sync, P, Track<Open>>,
153 request::Admitted<exec::Sync, P, Track<Finished>>,
154>;