ploidy_core/ir/views/
operation.rs1use std::marker::PhantomData;
2
3use petgraph::{
4 graph::NodeIndex,
5 visit::{Bfs, EdgeFiltered, EdgeRef, VisitMap, Visitable},
6};
7
8use crate::{
9 ir::{
10 graph::{IrGraph, IrGraphG, IrGraphNode},
11 types::{
12 IrOperation, IrParameter, IrParameterInfo, IrParameterStyle, IrRequest, IrResponse,
13 },
14 },
15 parse::{Method, path::PathSegment},
16};
17
18use super::{inline::InlineIrTypeView, ir::IrTypeView};
19
20#[derive(Debug)]
22pub struct IrOperationView<'a> {
23 graph: &'a IrGraph<'a>,
24 op: &'a IrOperation<'a>,
25}
26
27impl<'a> IrOperationView<'a> {
28 pub(in crate::ir) fn new(graph: &'a IrGraph<'a>, op: &'a IrOperation<'a>) -> Self {
29 Self { graph, op }
30 }
31
32 #[inline]
33 pub fn resource(&self) -> &'a str {
34 self.op.resource
35 }
36
37 #[inline]
38 pub fn id(&self) -> &'a str {
39 self.op.id
40 }
41
42 #[inline]
43 pub fn method(&self) -> Method {
44 self.op.method
45 }
46
47 #[inline]
48 pub fn path(&self) -> IrOperationViewPath<'_, 'a> {
49 IrOperationViewPath(self)
50 }
51
52 #[inline]
53 pub fn description(&self) -> Option<&'a str> {
54 self.op.description
55 }
56
57 #[inline]
59 pub fn query(&self) -> impl Iterator<Item = IrParameterView<'a, IrQueryParameter>> + '_ {
60 self.op.params.iter().filter_map(move |param| match param {
61 IrParameter::Query(info) => Some(IrParameterView::new(self.graph, info)),
62 _ => None,
63 })
64 }
65
66 #[inline]
68 pub fn request(&self) -> Option<IrRequestView<'a>> {
69 self.op.request.as_ref().map(|ty| match ty {
70 IrRequest::Json(ty) => {
71 let node = IrGraphNode::from_ref(self.graph.spec, ty.as_ref());
72 IrRequestView::Json(IrTypeView::new(self.graph, self.graph.indices[&node]))
73 }
74 IrRequest::Multipart => IrRequestView::Multipart,
75 })
76 }
77
78 #[inline]
80 pub fn response(&self) -> Option<IrResponseView<'a>> {
81 self.op.response.as_ref().map(|ty| match ty {
82 IrResponse::Json(ty) => {
83 let node = IrGraphNode::from_ref(self.graph.spec, ty.as_ref());
84 IrResponseView::Json(IrTypeView::new(self.graph, self.graph.indices[&node]))
85 }
86 })
87 }
88
89 #[inline]
92 pub fn inlines(&self) -> impl Iterator<Item = InlineIrTypeView<'a>> {
93 let filtered = EdgeFiltered::from_fn(&self.graph.g, |r| {
95 !matches!(self.graph.g[r.target()], IrGraphNode::Schema(_))
96 });
97 let mut bfs = self.bfs();
98 std::iter::from_fn(move || bfs.next(&filtered)).filter_map(|index| {
99 match self.graph.g[index] {
100 IrGraphNode::Inline(ty) => Some(InlineIrTypeView::new(self.graph, index, ty)),
101 _ => None,
102 }
103 })
104 }
105
106 fn bfs(&self) -> Bfs<NodeIndex, <IrGraphG<'a> as Visitable>::Map> {
107 let stack = self
111 .op
112 .types()
113 .map(|ty| IrGraphNode::from_ref(self.graph.spec, ty.as_ref()))
114 .map(|node| self.graph.indices[&node])
115 .collect();
116 let mut discovered = self.graph.g.visit_map();
117 for &index in &stack {
118 discovered.visit(index);
119 }
120 Bfs { stack, discovered }
121 }
122}
123
124#[derive(Clone, Copy, Debug)]
126pub struct IrOperationViewPath<'view, 'a>(&'view IrOperationView<'a>);
127
128impl<'view, 'a> IrOperationViewPath<'view, 'a> {
129 #[inline]
130 pub fn segments(self) -> std::slice::Iter<'view, PathSegment<'a>> {
131 self.0.op.path.iter()
132 }
133
134 #[inline]
136 pub fn params(self) -> impl Iterator<Item = IrParameterView<'a, IrPathParameter>> + 'view {
137 self.0
138 .op
139 .params
140 .iter()
141 .filter_map(move |param| match param {
142 IrParameter::Path(info) => Some(IrParameterView::new(self.0.graph, info)),
143 _ => None,
144 })
145 }
146}
147
148#[derive(Debug)]
150pub struct IrParameterView<'a, T> {
151 graph: &'a IrGraph<'a>,
152 info: &'a IrParameterInfo<'a>,
153 phantom: PhantomData<T>,
154}
155
156impl<'a, T> IrParameterView<'a, T> {
157 pub(in crate::ir) fn new(graph: &'a IrGraph<'a>, info: &'a IrParameterInfo<'a>) -> Self {
158 Self {
159 graph,
160 info,
161 phantom: PhantomData,
162 }
163 }
164
165 #[inline]
166 pub fn name(&self) -> &'a str {
167 self.info.name
168 }
169
170 #[inline]
171 pub fn ty(&self) -> IrTypeView<'a> {
172 let graph = self.graph;
173 let node = IrGraphNode::from_ref(graph.spec, self.info.ty.as_ref());
174 IrTypeView::new(graph, graph.indices[&node])
175 }
176
177 #[inline]
178 pub fn required(&self) -> bool {
179 self.info.required
180 }
181
182 #[inline]
183 pub fn style(&self) -> Option<IrParameterStyle> {
184 self.info.style
185 }
186}
187
188#[derive(Clone, Copy, Debug)]
190pub enum IrPathParameter {}
191
192#[derive(Clone, Copy, Debug)]
194pub enum IrQueryParameter {}
195
196#[derive(Debug)]
198pub enum IrRequestView<'a> {
199 Json(IrTypeView<'a>),
200 Multipart,
201}
202
203#[derive(Debug)]
205pub enum IrResponseView<'a> {
206 Json(IrTypeView<'a>),
207}