// The other half of gRPC's rich errors: reading `grpc-status-details-bin` back into the
// `google.rpc.Status` the server packed — its code, its message, and the `Any` details a
// client can decode into whatever message they carry.
///|
/// A `google.rpc.Status` as it arrives in the `grpc-status-details-bin` trailer: the status
/// code, the message, and the serialized `google.protobuf.Any` details in order.
pub(all) struct StatusDetails {
code : Int32
message : String
details : Array[Bytes]
} derive(Eq, Debug)
///|
pub extend StatusDetails with Eq::{not_equal, equal}
///|
pub extend StatusDetails with Debug::{to_repr}
///|
/// Decode a `google.rpc.Status` (`code` = 1, `message` = 2, repeated `details` = 3). `None`
/// when the bytes are not one: a trailer that will not decode is worse than no trailer, but
/// it is not something to fail a call over, since the status itself already came in the
/// `grpc-status` header.
pub fn decode_status_details(body : BytesView) -> StatusDetails? {
let r = PbReader::new(body.to_owned())
let mut code = 0
let mut message = ""
let details : Array[Bytes] = []
let parsed = try {
while !r.eof() {
match r.read_tag() {
(1, Varint) => code = r.read_int32()
(2, LengthDelim) => message = r.read_string()
(3, LengthDelim) => details.push(r.read_bytes())
(_, w) => r.skip(w)
}
}
true
} catch {
_ => false
}
if parsed {
Some({ code, message, details, })
} else {
None
}
}
///|
/// The type URL of a `google.protobuf.Any` detail: field 1 of the `Any`, the message name
/// such as `type.googleapis.com/greet.Badge`, or `None` when the bytes are not an `Any`.
pub fn detail_type_url(detail : BytesView) -> String? {
let r = PbReader::new(detail.to_owned())
let found = try {
while !r.eof() {
match r.read_tag() {
(1, LengthDelim) => return Some(r.read_string())
(_, w) => r.skip(w)
}
}
None
} catch {
_ => None
}
found
}
///|
/// The body of a `google.protobuf.Any` detail (field 2): the message the type URL names,
/// ready for that message's own `decode`.
pub fn detail_body(detail : BytesView) -> Bytes? {
let r = PbReader::new(detail.to_owned())
let found = try {
while !r.eof() {
match r.read_tag() {
(2, LengthDelim) => return Some(r.read_bytes())
(_, w) => r.skip(w)
}
}
None
} catch {
_ => None
}
found
}