# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: v1alpha1/signature.proto
# plugin: python-betterproto
# This file has been @generated

from dataclasses import dataclass
from typing import (
    TYPE_CHECKING,
    Dict,
    List,
    Optional,
)

import betterproto
import grpclib
from betterproto.grpc.grpclib_server import ServiceBase

from .. import graph as _graph__


if TYPE_CHECKING:
    import grpclib.server
    from betterproto.grpc.grpclib_client import MetadataLike
    from grpclib.metadata import Deadline


@dataclass(eq=False, repr=False)
class FunctionDeclaration(betterproto.Message):
    """
    Information about a function: its polymorphic [TypeScheme], user-readable
     description, and port ordering (for debug/display purposes, not used by
     the typechecker).
    """

    type_scheme: "_graph__.TypeScheme" = betterproto.message_field(2)
    """/ Polymorphic type scheme describing all possible input/output types"""

    description: str = betterproto.string_field(3)
    """Human-readable documentation"""

    input_order: List[str] = betterproto.string_field(4)
    """Order in which to display input ports"""

    output_order: List[str] = betterproto.string_field(5)
    """Order in which to display output ports"""


@dataclass(eq=False, repr=False)
class ListFunctionsRequest(betterproto.Message):
    """
    Request to list the functions known to a Runtime, optionally filtering by a Location
    """

    loc: "_graph__.Location" = betterproto.message_field(1)
    """
    Filter to only report functions available in the specified location or children
     thereof. (The default/empty location means the root, i.e. all functions.)
    """


@dataclass(eq=False, repr=False)
class ListFunctionsResponse(betterproto.Message):
    """
    aka the "Signature" of a Runtime: the `FunctionDeclaration`s and
     descendant `Location`s that it knows.
    """

    root: "Namespace" = betterproto.message_field(1)
    """
    Every function the runtime can run, and the locations in which it can run each
    """

    aliases: Dict[str, "_graph__.TypeScheme"] = betterproto.map_field(
        2, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """Named aliases for polymorphic types"""

    scopes: List["_graph__.Location"] = betterproto.message_field(3)
    """All the locations the Runtime knows."""


@dataclass(eq=False, repr=False)
class InferTypeRequest(betterproto.Message):
    """
    Request to infer the type of a graph (used for `TypeInference::InferType`)
    """

    value: "_graph__.Value" = betterproto.message_field(1)
    """Value whose type (scheme) to infer"""

    loc: "_graph__.Location" = betterproto.message_field(2)
    """
    Sub-location of the runtime in to which to check. If this leads to
     `ErrorVariant::unknown_function` errors that do not occur without the
     location, this indicates usage of functions available only outside that
     location i.e. these would use an escape hatch if the Graph were run.
    """


@dataclass(eq=False, repr=False)
class InferTypeResponse(betterproto.Message):
    """
    Result of inferring the type of a value via `TypeInference::InferType`
    """

    success: "InferTypeSuccess" = betterproto.message_field(1, group="response")
    """
    Inference succeeded, return the type-annotated value and inferred type (scheme)
    """

    error: "TypeErrors" = betterproto.message_field(2, group="response")
    """Type inference failed because of one or more type errors"""


@dataclass(eq=False, repr=False)
class InferTypeSuccess(betterproto.Message):
    """A type successfully inferred by `TypeInference::InferType`"""

    value: "_graph__.Value" = betterproto.message_field(1)
    """
    The value whose type was inferred. The same as the value passed in,
     except that any `Value::graph`s within will have their edges annotated
     with the inferred types (`Edge::edge_type`).
    """

    type_scheme: "_graph__.TypeScheme" = betterproto.message_field(2)
    """
    Type scheme inferred for the value, i.e. explicitly listing any type variables
     over which the value is polymorphic. (E.g. if the value is an empty list.)
    """


@dataclass(eq=False, repr=False)
class GraphWithInputs(betterproto.Message):
    """
    A graph with (optionally) input values for it. Used for
     `InferGraphTypesRequest`s and `InferGraphTypesResponse`.
    """

    graph: "_graph__.Graph" = betterproto.message_field(1)
    """The graph"""

    inputs: Optional["_graph__.StructValue"] = betterproto.message_field(
        2, optional=True
    )
    """Optionally, input values to feed to the graph"""


@dataclass(eq=False, repr=False)
class InferGraphTypesRequest(betterproto.Message):
    """
    Used by `tierkreis-typecheck` Rust(PYO3)/python interop library
     to request type inference of a graph with input values.
    """

    gwi: "GraphWithInputs" = betterproto.message_field(1)
    """Graph and inputs whose types to infer"""

    functions: "Namespace" = betterproto.message_field(2)
    """The signature of functions to check against."""


@dataclass(eq=False, repr=False)
class InferGraphTypesResponse(betterproto.Message):
    """
    Used by `tierkreis-typecheck` Rust(PYO3)/python interop library
     to report results of type inference on a graph with input values.
    """

    success: "GraphWithInputs" = betterproto.message_field(1, group="response")
    """Inference was successful, return the type"""

    error: "TypeErrors" = betterproto.message_field(2, group="response")
    """Inference failed due to one or more `TierkreisTypeError`s"""


@dataclass(eq=False, repr=False)
class Empty(betterproto.Message):
    """
    This is supposed to be `google.protobuf.Empty` but unfortunately there is no
     support for this in `betterproto` yet.
    """

    pass


@dataclass(eq=False, repr=False)
class GraphLocation(betterproto.Message):
    """
    A series of these identifies where in a `Value::graph` or `GraphWithInputs`
     was the cause of a `TierkreisTypeError`.
    """

    vec_index: int = betterproto.uint32_field(2, group="location")
    """
    Where the previous location(s) identify a `Value::vec`, identifies one element by index
    """

    node_idx: int = betterproto.uint32_field(4, group="location")
    """
    Where the previous location(s) identify a graph, the error is in the indexed node.
     (If-and-only-if the node is a Box or Const, may be followed by more `GraphLocation`s.)
    """

    edge: "_graph__.Edge" = betterproto.message_field(5, group="location")
    """
    Where the previous location(s) identify a graph, the error is on the indicated edge.
     (Will end the sequence of `GraphLocation`s.)
    """

    input: "Empty" = betterproto.message_field(6, group="location")
    """
    Where previous location(s) identify a graph, the error is in the input node
    """

    output: "Empty" = betterproto.message_field(7, group="location")
    """
    Where previous location(s) identify a graph, the error is in the output node
    """

    struct_field: str = betterproto.string_field(8, group="location")
    """
    Where the previous location(s) identify a struct value (e.g. inside a Const),
     the error is in the named field of that struct
    """

    pair_first: "Empty" = betterproto.message_field(9, group="location")
    """
    Where the previous location(s) identify a `Value::pair`, the error is in the first element
    """

    pair_second: "Empty" = betterproto.message_field(10, group="location")
    """
    Where the previous location(s) identify a `Value::pair`, the error is in the second element
    """

    map_key: "Empty" = betterproto.message_field(11, group="location")
    """
    Where the previous location(s) identify a `Value::map`, the error is in one of the keys
     (does not specify which)
    """

    map_value: "Empty" = betterproto.message_field(12, group="location")
    """
    Where the previous location(s) identify a `Value::map`, the error is in one of the values
     (does not specify which)
    """

    input_value: str = betterproto.string_field(13, group="location")
    """
    For `TypeInference::InferType`,
     indicates the error is in one of the `GraphWithInputs::inputs`
    """


@dataclass(eq=False, repr=False)
class TypeErrors(betterproto.Message):
    """A Collection of `TypeError`s"""

    errors: List["TierkreisTypeError"] = betterproto.message_field(1)
    """List of errors"""


@dataclass(eq=False, repr=False)
class UnifyError(betterproto.Message):
    """`ErrorVariant` that two types failed to unify."""

    expected: "_graph__.Type" = betterproto.message_field(1)
    """The type that was expected."""

    found: "_graph__.Type" = betterproto.message_field(2)
    """The type that was actually inferred."""


@dataclass(eq=False, repr=False)
class TypeVarError(betterproto.Message):
    """
    `ErrorVariant` that a type scheme is ill-formed because it refers to an unknown
     type variable.
    """

    variable: "_graph__.TypeSchemeVar" = betterproto.message_field(1)
    """The unknown type variable."""

    type_scheme: "_graph__.TypeScheme" = betterproto.message_field(2)
    """The ill-formed type scheme."""


@dataclass(eq=False, repr=False)
class ErrorVariant(betterproto.Message):
    """Errors that can occur during type checking."""

    unify: "UnifyError" = betterproto.message_field(1, group="error")
    """Two types failed to unify."""

    kind: str = betterproto.string_field(2, group="error")
    """A type scheme is ill-formed due to a kind mismatch."""

    unknown_function: "_graph__.FunctionName" = betterproto.message_field(
        3, group="error"
    )
    """A graph referred to an unknown function."""

    unknown_type_var: "TypeVarError" = betterproto.message_field(4, group="error")
    """
    A type scheme is ill-formed because it refers to an unknown type variable.
    """

    bound: str = betterproto.string_field(5, group="error")
    """
    A type constraint (`LacksConstraint` or `PartitionConstraint`) is unsatisfiable.
    """


@dataclass(eq=False, repr=False)
class TierkreisTypeError(betterproto.Message):
    """
    An error preventing type inference in a graph passed to `TypeInference::InferType`
     or `tierkreis.v1alpha1.runtime.Runime.RunGraph`
    """

    variant: "ErrorVariant" = betterproto.message_field(1)
    """Detail of the error"""

    location: List["GraphLocation"] = betterproto.message_field(2)
    """
    Identifies where in the value/graph the error occurred.
     Locations go from outermost to innermost in nested const/box graphs.
    """


@dataclass(eq=False, repr=False)
class NamespaceItem(betterproto.Message):
    """
    A `FunctionDeclaration` with a set of `Location`s at which
     the function is supported.
    """

    decl: "FunctionDeclaration" = betterproto.message_field(1)
    """
    Declaration of the function, including typescheme;
     identical at all `locations`
    """

    locations: List["_graph__.Location"] = betterproto.message_field(2)
    """The locations (aka scopes) at which the function is supported"""


@dataclass(eq=False, repr=False)
class Namespace(betterproto.Message):
    """
    Tree-structured mapping (sharing common prefixes) from
     `tierkreis.v1alpha1.graph.FunctionName`s to `NamespaceItem`s
    """

    functions: Dict[str, "NamespaceItem"] = betterproto.map_field(
        1, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """`NamespaceItem`s at this level of the qualified-name hierarchy"""

    subspaces: Dict[str, "Namespace"] = betterproto.map_field(
        2, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """
    Mappings for subtrees of the name hierarchy, i.e. for qualnames
     with a longer prefix (the map key being the next atom of prefix)
    """


class SignatureStub(betterproto.ServiceStub):
    async def list_functions(
        self,
        list_functions_request: "ListFunctionsRequest",
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "ListFunctionsResponse":
        return await self._unary_unary(
            "/tierkreis.v1alpha1.signature.Signature/ListFunctions",
            list_functions_request,
            ListFunctionsResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )


class TypeInferenceStub(betterproto.ServiceStub):
    async def infer_type(
        self,
        infer_type_request: "InferTypeRequest",
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "InferTypeResponse":
        return await self._unary_unary(
            "/tierkreis.v1alpha1.signature.TypeInference/InferType",
            infer_type_request,
            InferTypeResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )


class SignatureBase(ServiceBase):

    async def list_functions(
        self, list_functions_request: "ListFunctionsRequest"
    ) -> "ListFunctionsResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def __rpc_list_functions(
        self,
        stream: "grpclib.server.Stream[ListFunctionsRequest, ListFunctionsResponse]",
    ) -> None:
        request = await stream.recv_message()
        response = await self.list_functions(request)
        await stream.send_message(response)

    def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
        return {
            "/tierkreis.v1alpha1.signature.Signature/ListFunctions": grpclib.const.Handler(
                self.__rpc_list_functions,
                grpclib.const.Cardinality.UNARY_UNARY,
                ListFunctionsRequest,
                ListFunctionsResponse,
            ),
        }


class TypeInferenceBase(ServiceBase):

    async def infer_type(
        self, infer_type_request: "InferTypeRequest"
    ) -> "InferTypeResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def __rpc_infer_type(
        self, stream: "grpclib.server.Stream[InferTypeRequest, InferTypeResponse]"
    ) -> None:
        request = await stream.recv_message()
        response = await self.infer_type(request)
        await stream.send_message(response)

    def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
        return {
            "/tierkreis.v1alpha1.signature.TypeInference/InferType": grpclib.const.Handler(
                self.__rpc_infer_type,
                grpclib.const.Cardinality.UNARY_UNARY,
                InferTypeRequest,
                InferTypeResponse,
            ),
        }
