use serde::de;
use serde::de::DeserializeOwned;
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use url::Url;
use super::id::*;
use super::status::*;
use super::{Library, Script};
use super::{Resource, ResourceCommon};
use crate::client::Client;
use crate::errors::*;
mod args;
mod execution_status;
pub use self::args::*;
pub use self::execution_status::*;
#[derive(Clone, Debug, Deserialize, Resource, Serialize)]
#[api_name = "execution"]
#[non_exhaustive]
pub struct Execution {
#[serde(flatten)]
pub common: ResourceCommon,
pub resource: Id<Execution>,
pub status: ExecutionStatus,
pub execution: Data,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Data {
#[serde(default)]
pub outputs: Vec<Output>,
pub result: Option<serde_json::Value>,
#[serde(default)]
pub logs: Vec<LogEntry>,
#[serde(default)]
pub output_resources: Vec<OutputResource>,
#[serde(default)]
pub sources: Vec<Source>,
}
impl Data {
pub fn get<D: DeserializeOwned>(&self, name: &str) -> Result<D> {
for output in &self.outputs {
if output.name == name {
return output.get();
}
}
Err(Error::could_not_get_output(
name,
Error::OutputNotAvailable {},
))
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Source {
pub id: SourceId,
pub description: String,
}
impl<'de> Deserialize<'de> for Source {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Source;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "a list with a source ID and a description")
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: de::SeqAccess<'de>,
{
use serde::de::Error;
let id = visitor
.next_element()?
.ok_or_else(|| V::Error::custom("no id field in source"))?;
let description = visitor.next_element()?.ok_or_else(|| {
V::Error::custom("no description field in source")
})?;
Ok(Source { id, description })
}
}
deserializer.deserialize_seq(Visitor)
}
}
impl Serialize for Source {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(&self.id)?;
seq.serialize_element(&self.description)?;
seq.end()
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum SourceId {
Library(Id<Library>),
Script(Id<Script>),
}
impl SourceId {
pub fn dashboard_url(&self) -> Url {
match self {
SourceId::Library(id) => id.dashboard_url(),
SourceId::Script(id) => id.dashboard_url(),
}
}
pub async fn fetch_source_code(&self, client: &Client) -> Result<String> {
match *self {
SourceId::Library(ref id) => Ok(client.fetch(id).await?.source_code),
SourceId::Script(ref id) => Ok(client.fetch(id).await?.source_code),
}
}
}
impl fmt::Display for SourceId {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SourceId::Library(ref id) => id.fmt(fmt),
SourceId::Script(ref id) => id.fmt(fmt),
}
}
}
impl<'de> Deserialize<'de> for SourceId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = SourceId;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "a script or library ID")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
if value.starts_with(Library::id_prefix()) {
let id = value
.parse()
.map_err(|e| de::Error::custom(format!("{}", e)))?;
Ok(SourceId::Library(id))
} else if value.starts_with(Script::id_prefix()) {
let id = value
.parse()
.map_err(|e| de::Error::custom(format!("{}", e)))?;
Ok(SourceId::Script(id))
} else {
Err(de::Error::custom("expected script or library ID"))
}
}
}
deserializer.deserialize_str(Visitor)
}
}
impl Serialize for SourceId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
SourceId::Library(ref id) => id.serialize(serializer),
SourceId::Script(ref id) => id.serialize(serializer),
}
}
}