xref: /linux/tools/net/sunrpc/xdrgen/generators/pointer.py (revision fcc202d324e5d2a21557ddd20fc3f96e08c4f72d)
1#!/usr/bin/env python3
2# ex: set filetype=python:
3
4"""Generate code to handle XDR pointer types"""
5
6from jinja2 import Environment
7
8from generators import SourceGenerator, kernel_c_type
9from generators import create_jinja2_environment, get_jinja2_template
10
11from xdr_ast import _XdrBasic, _XdrString
12from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
13from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
14from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration
15from xdr_ast import public_apis, get_header_name
16from xdr_ast import pages_members, pages_member_maxsize, pages_member_is_decoded
17
18
19def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None:
20    """Emit a declaration pair for an XDR pointer type"""
21    if node.name in public_apis:
22        template = get_jinja2_template(environment, "declaration", "close")
23        print(template.render(name=node.name))
24
25
26def emit_pointer_member_definition(
27    environment: Environment, field: _XdrDeclaration, struct_name: str, peer: str
28) -> None:
29    """Emit a definition for one field in an XDR struct"""
30    if peer == "server" and pages_member_is_decoded(struct_name, field.name):
31        template = get_jinja2_template(environment, "definition", "pages_opaque")
32        print(template.render(name=field.name))
33        return
34    if isinstance(field, _XdrBasic):
35        template = get_jinja2_template(environment, "definition", field.template)
36        print(
37            template.render(
38                name=field.name,
39                type=kernel_c_type(field.spec),
40                classifier=field.spec.c_classifier,
41            )
42        )
43    elif isinstance(field, _XdrFixedLengthOpaque):
44        template = get_jinja2_template(environment, "definition", field.template)
45        print(
46            template.render(
47                name=field.name,
48                size=field.size,
49            )
50        )
51    elif isinstance(field, _XdrVariableLengthOpaque):
52        template = get_jinja2_template(environment, "definition", field.template)
53        print(template.render(name=field.name))
54    elif isinstance(field, _XdrString):
55        template = get_jinja2_template(environment, "definition", field.template)
56        print(template.render(name=field.name))
57    elif isinstance(field, _XdrFixedLengthArray):
58        template = get_jinja2_template(environment, "definition", field.template)
59        print(
60            template.render(
61                name=field.name,
62                type=kernel_c_type(field.spec),
63                size=field.size,
64            )
65        )
66    elif isinstance(field, _XdrVariableLengthArray):
67        template = get_jinja2_template(environment, "definition", field.template)
68        print(
69            template.render(
70                name=field.name,
71                type=kernel_c_type(field.spec),
72                classifier=field.spec.c_classifier,
73            )
74        )
75    elif isinstance(field, _XdrOptionalData):
76        template = get_jinja2_template(environment, "definition", field.template)
77        print(
78            template.render(
79                name=field.name,
80                type=kernel_c_type(field.spec),
81                classifier=field.spec.c_classifier,
82            )
83        )
84
85
86def emit_pointer_definition(
87    environment: Environment, node: _XdrPointer, peer: str
88) -> None:
89    """Emit a definition for an XDR pointer type"""
90    template = get_jinja2_template(environment, "definition", "open")
91    print(template.render(name=node.name))
92
93    for field in node.fields[0:-1]:
94        emit_pointer_member_definition(environment, field, node.name, peer)
95
96    template = get_jinja2_template(environment, "definition", "close")
97    print(template.render(name=node.name))
98
99
100def emit_pointer_member_decoder(
101    environment: Environment,
102    field: _XdrDeclaration,
103    struct_name: str,
104    peer: str,
105) -> None:
106    """Emit a decoder for one field in an XDR pointer"""
107    if peer == "server" and pages_member_is_decoded(struct_name, field.name):
108        template = get_jinja2_template(environment, "decoder", "pages_opaque")
109        print(
110            template.render(
111                name=field.name,
112                maxsize=pages_member_maxsize(field),
113            )
114        )
115        return
116    if isinstance(field, _XdrBasic):
117        template = get_jinja2_template(environment, "decoder", field.template)
118        print(
119            template.render(
120                name=field.name,
121                type=field.spec.type_name,
122                classifier=field.spec.c_classifier,
123            )
124        )
125    elif isinstance(field, _XdrFixedLengthOpaque):
126        template = get_jinja2_template(environment, "decoder", field.template)
127        print(
128            template.render(
129                name=field.name,
130                size=field.size,
131            )
132        )
133    elif isinstance(field, _XdrVariableLengthOpaque):
134        template = get_jinja2_template(environment, "decoder", field.template)
135        print(
136            template.render(
137                name=field.name,
138                maxsize=field.maxsize,
139            )
140        )
141    elif isinstance(field, _XdrString):
142        template = get_jinja2_template(environment, "decoder", field.template)
143        print(
144            template.render(
145                name=field.name,
146                maxsize=field.maxsize,
147            )
148        )
149    elif isinstance(field, _XdrFixedLengthArray):
150        template = get_jinja2_template(environment, "decoder", field.template)
151        print(
152            template.render(
153                name=field.name,
154                type=field.spec.type_name,
155                size=field.size,
156                classifier=field.spec.c_classifier,
157            )
158        )
159    elif isinstance(field, _XdrVariableLengthArray):
160        template = get_jinja2_template(environment, "decoder", field.template)
161        print(
162            template.render(
163                name=field.name,
164                type=field.spec.type_name,
165                maxsize=field.maxsize,
166                classifier=field.spec.c_classifier,
167            )
168        )
169    elif isinstance(field, _XdrOptionalData):
170        template = get_jinja2_template(environment, "decoder", field.template)
171        print(
172            template.render(
173                name=field.name,
174                type=field.spec.type_name,
175                classifier=field.spec.c_classifier,
176            )
177        )
178
179
180def emit_pointer_decoder(
181    environment: Environment, node: _XdrPointer, peer: str
182) -> None:
183    """Emit one decoder function for an XDR pointer type"""
184    template = get_jinja2_template(environment, "decoder", "open")
185    print(template.render(name=node.name))
186
187    for field in node.fields[0:-1]:
188        emit_pointer_member_decoder(environment, field, node.name, peer)
189
190    template = get_jinja2_template(environment, "decoder", "close")
191    print(template.render())
192
193
194def emit_pointer_member_encoder(
195    environment: Environment,
196    field: _XdrDeclaration,
197    struct_name: str,
198    peer: str,
199) -> None:
200    """Emit an encoder for one field in a XDR pointer"""
201    if (struct_name, field.name) in pages_members:
202        if peer != "server":
203            raise NotImplementedError(
204                "pragma pages is server-side only; "
205                + peer
206                + " generation is not yet supported"
207            )
208        # Both representations carry the length field, which is all the
209        # pages encoder reads, so pages_member_is_decoded() does not
210        # gate this site.
211        template = get_jinja2_template(environment, "encoder", "pages_opaque")
212        print(
213            template.render(
214                name=field.name,
215                maxsize=pages_member_maxsize(field),
216            )
217        )
218        return
219    if isinstance(field, _XdrBasic):
220        template = get_jinja2_template(environment, "encoder", field.template)
221        print(
222            template.render(
223                name=field.name,
224                type=field.spec.type_name,
225            )
226        )
227    elif isinstance(field, _XdrFixedLengthOpaque):
228        template = get_jinja2_template(environment, "encoder", field.template)
229        print(
230            template.render(
231                name=field.name,
232                size=field.size,
233            )
234        )
235    elif isinstance(field, _XdrVariableLengthOpaque):
236        template = get_jinja2_template(environment, "encoder", field.template)
237        print(
238            template.render(
239                name=field.name,
240                maxsize=field.maxsize,
241            )
242        )
243    elif isinstance(field, _XdrString):
244        template = get_jinja2_template(environment, "encoder", field.template)
245        print(
246            template.render(
247                name=field.name,
248                maxsize=field.maxsize,
249            )
250        )
251    elif isinstance(field, _XdrFixedLengthArray):
252        template = get_jinja2_template(environment, "encoder", field.template)
253        print(
254            template.render(
255                name=field.name,
256                type=field.spec.type_name,
257                size=field.size,
258            )
259        )
260    elif isinstance(field, _XdrVariableLengthArray):
261        template = get_jinja2_template(environment, "encoder", field.template)
262        print(
263            template.render(
264                name=field.name,
265                type=field.spec.type_name,
266                maxsize=field.maxsize,
267            )
268        )
269    elif isinstance(field, _XdrOptionalData):
270        template = get_jinja2_template(environment, "encoder", field.template)
271        print(
272            template.render(
273                name=field.name,
274                type=field.spec.type_name,
275                classifier=field.spec.c_classifier,
276            )
277        )
278
279
280def emit_pointer_encoder(
281    environment: Environment, node: _XdrPointer, peer: str
282) -> None:
283    """Emit one encoder function for an XDR pointer type"""
284    template = get_jinja2_template(environment, "encoder", "open")
285    print(template.render(name=node.name))
286
287    for field in node.fields[0:-1]:
288        emit_pointer_member_encoder(environment, field, node.name, peer)
289
290    template = get_jinja2_template(environment, "encoder", "close")
291    print(template.render())
292
293
294def emit_pointer_maxsize(environment: Environment, node: _XdrPointer) -> None:
295    """Emit one maxsize macro for an XDR pointer type"""
296    macro_name = get_header_name().upper() + "_" + node.name + "_sz"
297    template = get_jinja2_template(environment, "maxsize", "pointer")
298    print(
299        template.render(
300            macro=macro_name,
301            width=" + ".join(node.symbolic_width()),
302        )
303    )
304
305
306class XdrPointerGenerator(SourceGenerator):
307    """Generate source code for XDR pointer"""
308
309    def __init__(self, language: str, peer: str):
310        """Initialize an instance of this class"""
311        self.environment = create_jinja2_environment(language, "pointer")
312        self.peer = peer
313
314    def emit_declaration(self, node: _XdrPointer) -> None:
315        """Emit one declaration pair for an XDR pointer type"""
316        emit_pointer_declaration(self.environment, node)
317
318    def emit_definition(self, node: _XdrPointer) -> None:
319        """Emit one declaration for an XDR pointer type"""
320        emit_pointer_definition(self.environment, node, self.peer)
321
322    def emit_decoder(self, node: _XdrPointer) -> None:
323        """Emit one decoder function for an XDR pointer type"""
324        emit_pointer_decoder(self.environment, node, self.peer)
325
326    def emit_encoder(self, node: _XdrPointer) -> None:
327        """Emit one encoder function for an XDR pointer type"""
328        emit_pointer_encoder(self.environment, node, self.peer)
329
330    def emit_maxsize(self, node: _XdrPointer) -> None:
331        """Emit one maxsize macro for an XDR pointer type"""
332        emit_pointer_maxsize(self.environment, node)
333