Skip to main content

rustev_contract/
reason.rs

1//! Retained runtime reasons, `rustev.runtime-reason/1` (spec 004, 3.2): a
2//! historical runtime observation supplied to the core in place of an
3//! output. Only the four runtime reasons are accepted; a reason is never a
4//! backend output and never predicts a candidate's failure.
5
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10use crate::definition::ReasonKind;
11use crate::judgment::Unresolved;
12use crate::limits::RECORD_V1;
13use crate::schema;
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
16#[serde(deny_unknown_fields)]
17pub struct RuntimeReasonDoc {
18    pub schema: String,
19    pub reason: Unresolved,
20}
21
22crate::document::document!(RuntimeReasonDoc, schema::RUNTIME_REASON, RECORD_V1);
23
24/// A reason only a runtime reports: backend unavailable, invalid backend
25/// output, budget exhausted, deadline exceeded.
26pub fn is_runtime_reason(kind: ReasonKind) -> bool {
27    matches!(
28        kind,
29        ReasonKind::BackendUnavailable
30            | ReasonKind::InvalidBackendOutput
31            | ReasonKind::BudgetExhausted
32            | ReasonKind::DeadlineExceeded
33    )
34}
35
36/// The reason is not one of the four runtime reasons.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct NotARuntimeReason(pub ReasonKind);
39
40impl fmt::Display for NotARuntimeReason {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "{} is not a runtime reason", self.0.name())
43    }
44}
45
46impl std::error::Error for NotARuntimeReason {}
47
48impl RuntimeReasonDoc {
49    pub fn new(reason: Unresolved) -> Result<Self, NotARuntimeReason> {
50        let doc = Self {
51            schema: schema::RUNTIME_REASON.into(),
52            reason,
53        };
54        doc.check()?;
55        Ok(doc)
56    }
57
58    /// Refuse anything but the four runtime reasons.
59    pub fn check(&self) -> Result<(), NotARuntimeReason> {
60        let k = self.reason.kind();
61        if is_runtime_reason(k) {
62            Ok(())
63        } else {
64            Err(NotARuntimeReason(k))
65        }
66    }
67}