mod generated;
pub use generated::*;
use serde::{Deserialize, Serialize};
use crate::rpc::{Any, Status};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(from = "Wire", into = "Wire")]
pub struct Operation {
pub name: String,
pub metadata: Option<Any>,
pub done: bool,
pub result: Option<OperationResult>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum OperationResult {
Error(Status),
Response(Any),
}
#[derive(Default, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct Wire {
#[serde(skip_serializing_if = "String::is_empty")]
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<Any>,
#[serde(skip_serializing_if = "std::ops::Not::not")]
done: bool,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<Status>,
#[serde(skip_serializing_if = "Option::is_none")]
response: Option<Any>,
}
impl From<Wire> for Operation {
fn from(w: Wire) -> Self {
let result = match (w.error, w.response) {
(Some(error), _) => Some(OperationResult::Error(error)),
(None, Some(response)) => Some(OperationResult::Response(response)),
(None, None) => None,
};
Self {
name: w.name,
metadata: w.metadata,
done: w.done,
result,
}
}
}
impl From<Operation> for Wire {
fn from(o: Operation) -> Self {
let (error, response) = match o.result {
Some(OperationResult::Error(e)) => (Some(e), None),
Some(OperationResult::Response(r)) => (None, Some(r)),
None => (None, None),
};
Self {
name: o.name,
metadata: o.metadata,
done: o.done,
error,
response,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_operation_reads_its_result() {
let done: Operation = serde_json::from_str(
r#"{"name":"projects/p/zones/z/operations/op-1","done":true,"response":{"@type":"type.googleapis.com/x.Y","name":"n"},"unknown":1}"#,
)
.unwrap();
assert!(done.done);
let Some(OperationResult::Response(any)) = &done.result else {
panic!("{done:?}");
};
assert_eq!(any.type_name(), "x.Y");
let again: Operation =
serde_json::from_str(&serde_json::to_string(&done).unwrap()).unwrap();
assert_eq!(again, done);
let running: Operation = serde_json::from_str(r#"{"name":"n"}"#).unwrap();
assert!(!running.done && running.result.is_none());
}
}