blob: f640f5f8fb54e41d0da13fb0155c73325aa73d7b [file]
{{/*
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
*/}}
{{ define "UnionDeclaration" -}}
class {{ .PythonName }}:
{{- if .DocComments }}
"""
{{- range .DocComments }}
{{ . | escapeQuotes | trimSpace | indentNonEmpty4 }}
{{- end }}
"""
{{- end }}
{{- range .PythonMembers }}
{{- if .DocComments }}
"""
{{- range .DocComments }}
{{ . | escapeQuotes | trimSpace | indentNonEmpty4 }}
{{- end }}
"""
{{- end }}
_{{ .PythonName }}: typing.Optional[{{ .PythonType.PythonName }}]
{{- end }}
__fidl_kind__ = "union"
__fidl_type__ = "{{ .PythonName }}"
__fidl_raw_type__ = "{{ .Name }}"
_is_result = {{ if .IsResult }}True{{ else }}False{{ end }}
def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
return False
{{ range .PythonMembers -}}
if self.{{ .PythonName }} != other.{{ .PythonName }}:
return False
{{ end -}}
return True
def __repr__(self) -> str:
"""Returns the union repr in the format <'foo.bar.baz/FooUnion' object({value})>
If {value} is not set, will write None."""
variant = ""
{{- range .PythonMembers }}
if self.{{ .PythonName }}:
variant = f"{{ .PythonName }}={self.{{ .PythonName }}!r}"
{{- end }}
return f"<'{self.__fidl_type__}' object({variant})>"
{{ if .PythonMembers -}}
def __init__(
self,
{{- range .PythonMembers }}
{{ .PythonName }}: typing.Optional[{{ .PythonType.PythonName }}] = _UNDEFINED,
{{- end }}
_empty: typing.Optional[tuple[()]]=None,
):
object.__init__(self)
if _empty is not None:
return
number_of_variants = 0
variants = []
{{ range .PythonMembers -}}
if {{ .PythonName }} is not _UNDEFINED:
{{- if (eq .PythonType.PythonName "None") }}
self._{{ .PythonName }} = {{ .PythonName }}
variants.append('{{ .PythonName }}')
number_of_variants += 1
{{- else }}
if {{ .PythonName }} is not None:
self._{{ .PythonName }} = {{ .PythonName }}
variants.append('{{ .PythonName }}')
number_of_variants += 1
{{- end }}
{{ end -}}
if {{ if .IsResult }}number_of_variants > 1{{ else }}number_of_variants != 1{{ end }}:
raise TypeError(
f"Exactly one variant must be specified for {self.__fidl_raw_type__}: {variants}"
)
{{- end }}
{{ range .PythonMembers -}}
@property
def {{ .PythonName }}(self) -> {{ .PythonType.PythonName }} | None:
return getattr(self, "_{{ .PythonName }}", None)
{{ end -}}
# TODO(https://fxbug.dev/394421154): We should probably remove this method when we
# start making breaking changes.
def __getitem__(self, item: str): # type: ignore
if not isinstance(item, str):
raise TypeError("Subscripted item must be a string")
return getattr(self, item)
def encode(self) -> tuple[bytes, list[typing.Any]]:
return fidl.encode_struct(self, type(self)._encode, 16)
@classmethod
def decode(cls, data: bytes, handles: list[typing.Any]) -> typing.Self:
return fidl.decode_struct(data, handles, cls._decode, 16)
def _encode(self, encoder: fidl.Encoder, _offset: int) -> None:
{{- range .PythonMembers }}
if hasattr(self, "_{{ .PythonName }}"):
encoder.write_uint64({{ .Ordinal }}, _offset)
encoder.write_envelope(
getattr(self, "_{{ .PythonName }}"),
_offset + 8,
{{ .EncoderFn }},
{{ .TypeSize }},
{{ if .IsInline }}True{{ else }}False{{ end }},
)
return
{{- end }}
encoder.write_inline(_offset, b'\x00' * 16)
@classmethod
def _decode(cls, decoder: fidl.Decoder, _offset: int) -> typing.Self:
ordinal = decoder.read_uint64(_offset)
if ordinal == 0:
return cls({{ if .PythonMembers }}_empty=(){{ end }})
{{- range .PythonMembers }}
if ordinal == {{ .Ordinal }}:
val = decoder.read_envelope(
_offset + 8,
{{ .DecoderFn }},
{{ .TypeSize }},
)
return cls({{ .PythonName }}=val)
{{- end }}
# Skip unknown envelope
decoder.skip_envelope(_offset + 8)
raise ValueError(f"Unknown union ordinal {ordinal}")
{{ if .IsResult }}
def unwrap(self) -> {{ .PythonSuccessType.PythonName }}:
"""Returns the response if result does not contain an error. Otherwise, raises an exception."""
try:
if hasattr(self, "_framework_err") and self._framework_err is not None:
raise AssertionError(
f"{self.__fidl_raw_type__} framework error {self._framework_err}"
)
except AttributeError:
pass
try:
if hasattr(self, "_err") and self._err is not None:
raise AssertionError(f"{self.__fidl_raw_type__} error {self._err}")
except AttributeError:
pass
{{ if (eq .PythonSuccessType.PythonName "None") -}}
assert not hasattr(self, "_response") or self._response is None, f"Failed to unwrap {self.__fidl_raw_type__}. Response value present when it should be None: {self._response}"
{{ else -}}
assert self._response is not None, f"Failed to unwrap {self.__fidl_raw_type__}. Result does not contain an error or response."
return self._response
{{- end }}
{{ end }}
@classmethod
def make_default(cls) -> typing.Self:
{{ if .PythonMembers -}}
return cls(_empty=())
{{- else -}}
return cls()
{{- end }}
{{ end }}