use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::artifact::{ArtifactKind, RustCrateType};
use crate::identity::{
CMetadata, CrateName, CrateVersion, DependencyCMetadataJson, FeaturesJson, TargetTriple,
WireRustcVersion,
};
use crate::index::ArtifactIndexRow;
use crate::platform::Profile;
pub const CI_TARGET_TRIPLES: &[&str] = &[
"aarch64-apple-darwin",
"aarch64-apple-ios",
"aarch64-apple-ios-sim",
"aarch64-linux-android",
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
"aarch64-pc-windows-msvc",
"wasm32-unknown-unknown",
];
#[must_use]
pub fn is_ci_target(target: &str) -> bool {
CI_TARGET_TRIPLES.contains(&target)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RunnerFamily {
Linux,
MacOs,
Windows,
}
impl RunnerFamily {
pub const ALL: [Self; 3] = [Self::Linux, Self::MacOs, Self::Windows];
#[must_use]
pub const fn targets(self) -> &'static [&'static str] {
match self {
Self::Linux => &[
"aarch64-linux-android",
"x86_64-unknown-linux-gnu",
"aarch64-unknown-linux-gnu",
"wasm32-unknown-unknown",
],
Self::MacOs => &[
"aarch64-apple-darwin",
"aarch64-apple-ios",
"aarch64-apple-ios-sim",
],
Self::Windows => &["x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"],
}
}
}
#[must_use]
pub fn runner_family(target: &str) -> Option<RunnerFamily> {
RunnerFamily::ALL
.into_iter()
.find(|family| family.targets().contains(&target))
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct BuildTaskPayload {
pub task_id: String,
#[serde(default)]
pub attempt: u32,
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
#[serde(default)]
pub preserve_lockfile: bool,
#[serde(default)]
pub project_source: Option<ProjectSource>,
}
impl BuildTaskPayload {
#[must_use]
pub const fn uses_source_lockfile(&self) -> bool {
self.preserve_lockfile || self.project_source.is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ProjectSource {
pub url: String,
pub commit: String,
pub manifest_path: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactRecord {
pub compile_key: String,
pub c_metadata: CMetadata,
pub extra_filename: String,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub profile: Profile,
pub emit: Vec<String>,
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub dependency_c_metadata_json: DependencyCMetadataJson,
pub oci_reference: String,
pub oci_digest: String,
pub has_native: bool,
pub artifact_kind: ArtifactKind,
pub crate_types: Vec<RustCrateType>,
pub artifact_size: u64,
pub bundle_digest: String,
pub bundle_size: u64,
pub compile_millis: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct RegisterArtifactsRequest {
#[serde(default)]
pub task_id: Option<String>,
pub records: Vec<ArtifactRecord>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct EnqueueRequest {
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub downloads: u64,
pub source: EnqueueSource,
#[serde(default)]
pub depends_on: Vec<EnqueueDependency>,
#[serde(default)]
pub preserve_lockfile: bool,
#[serde(default)]
pub project_source: Option<ProjectSource>,
}
impl EnqueueRequest {
#[must_use]
pub const fn uses_source_lockfile(&self) -> bool {
self.preserve_lockfile || self.project_source.is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct EnqueueDependency {
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub enum EnqueueSource {
CrateUpdate,
RustcUpdate,
CacheMiss,
HumanRequest,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct EnqueueAdmission {
pub task_id: String,
pub challenge: String,
pub difficulty: u32,
pub request: EnqueueRequest,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct EnqueueTicket {
pub task_id: String,
pub challenge: String,
pub nonce: u64,
pub request: EnqueueRequest,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct AdmissionRequest {
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub entries: Vec<DependencyGraphEntry>,
#[serde(default)]
pub expanded_entries: Vec<ResolvedDependencyGraphEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct BuildCompleteReport {
pub task_id: String,
#[serde(default)]
pub attempt: u32,
pub success: bool,
pub error: Option<String>,
pub artifacts_uploaded: u32,
#[serde(default)]
pub github_run_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, ToSchema)]
pub struct DependencyGraphEntry {
pub crate_name: CrateName,
#[schema(value_type = String)]
pub version: semver::Version,
pub features: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, ToSchema)]
pub struct ResolvedDependencyGraphDependency {
pub crate_name: CrateName,
#[schema(value_type = String)]
pub version: semver::Version,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ResolvedDependencyGraphEntry {
pub crate_name: CrateName,
#[schema(value_type = String)]
pub version: semver::Version,
pub features: Vec<String>,
pub dependencies: Vec<ResolvedDependencyGraphDependency>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct PanicSwitch {
pub enabled: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SchedulerStatus {
pub pending: u32,
pub human_pending: u32,
pub dispatched: u32,
pub running: u32,
pub completed: u32,
pub failed: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct CrateRequest {
pub crate_name: CrateName,
#[serde(default)]
pub version: Option<CrateVersion>,
pub features_json: FeaturesJson,
pub turnstile_token: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateSearchHit {
pub crate_name: CrateName,
#[serde(default)]
pub description: Option<String>,
pub max_version: CrateVersion,
pub downloads: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateSearchResponse {
pub crates: Vec<CrateSearchHit>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateVersionsResponse {
pub versions: Vec<CrateVersion>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateFeature {
pub name: String,
pub implies: Vec<String>,
pub default: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateFeaturesResponse {
pub features: Vec<CrateFeature>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum TaskLane {
Miss,
Human,
}
impl TaskLane {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Miss => "miss",
Self::Human => "human",
}
}
#[must_use]
pub fn parse(value: &str) -> Option<Self> {
match value {
"miss" => Some(Self::Miss),
"human" => Some(Self::Human),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueueTaskStatus {
Pending,
Dispatched,
Running,
Completed,
Failed,
}
impl QueueTaskStatus {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Pending => "pending",
Self::Dispatched => "dispatched",
Self::Running => "running",
Self::Completed => "completed",
Self::Failed => "failed",
}
}
#[must_use]
pub fn parse(value: &str) -> Option<Self> {
match value {
"pending" => Some(Self::Pending),
"dispatched" => Some(Self::Dispatched),
"running" => Some(Self::Running),
"completed" => Some(Self::Completed),
"failed" => Some(Self::Failed),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum CrateRequestState {
Cached,
Queued,
AlreadyQueued,
Building,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateRequestTarget {
pub target: TargetTriple,
pub state: CrateRequestState,
#[serde(default)]
pub task_id: Option<String>,
#[serde(default)]
pub human_lane_position: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateRequestOutcome {
pub crate_name: CrateName,
pub version: CrateVersion,
pub rustc_version: WireRustcVersion,
pub targets: Vec<CrateRequestTarget>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct RequestStatus {
pub task_id: String,
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub lane: TaskLane,
pub status: QueueTaskStatus,
#[serde(default)]
pub human_lane_position: Option<u32>,
#[serde(default)]
pub preserve_lockfile: bool,
#[serde(default)]
pub project_source: Option<ProjectSource>,
}
impl RequestStatus {
#[must_use]
pub const fn uses_source_lockfile(&self) -> bool {
self.preserve_lockfile || self.project_source.is_some()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactIndexPage {
pub rows: Vec<ArtifactIndexRow>,
pub next_after: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct QueueSelector {
#[serde(default)]
pub task_ids: Vec<String>,
#[serde(default)]
pub status: Option<QueueTaskStatus>,
#[serde(default)]
pub target: Option<TargetTriple>,
#[serde(default, rename = "crate", alias = "crate_name")]
pub crate_name: Option<CrateName>,
#[serde(default, rename = "older_than", alias = "older_than_secs")]
pub older_than_secs: Option<u64>,
#[serde(default)]
pub limit: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct QueueMutationResult {
pub affected: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct QueueTask {
pub task_id: String,
pub crate_name: CrateName,
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub lane: TaskLane,
pub status: QueueTaskStatus,
pub attempt: u32,
pub error: String,
pub downloads: u64,
pub miss_count: u32,
pub request_count: u32,
pub dispatch_attempts: u32,
pub preserve_lockfile: bool,
#[serde(default)]
pub project_source: Option<ProjectSource>,
#[serde(default)]
pub github_run_id: Option<String>,
pub first_requested_at: String,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct AdminInFlight {
pub task_id: String,
pub crate_name: CrateName,
pub version: CrateVersion,
pub target: TargetTriple,
pub rustc_version: WireRustcVersion,
pub status: QueueTaskStatus,
pub attempt: u32,
pub dispatch_attempts: u32,
pub updated_at: String,
#[serde(default)]
pub github_run_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct AdminTargetStats {
pub target: TargetTriple,
pub completed_24h: u32,
pub failed_24h: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct AdminStatus {
pub pending_miss: u32,
pub pending_human: u32,
#[serde(default)]
pub oldest_pending_seconds: Option<u64>,
pub in_flight: Vec<AdminInFlight>,
pub targets: Vec<AdminTargetStats>,
pub panic_enabled: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct SchedulerSubmitResponse {
pub submitted: u32,
pub inserted: u32,
pub dropped: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CrateCoverage {
pub crate_name: CrateName,
#[serde(default)]
pub version: Option<CrateVersion>,
pub targets: Vec<CoverageTarget>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CoverageTarget {
pub target: TargetTriple,
pub artifacts: Vec<CoverageArtifact>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct CoverageArtifact {
pub version: CrateVersion,
pub features_json: FeaturesJson,
pub rustc_version: WireRustcVersion,
pub c_metadata: CMetadata,
pub bundle_size: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct PreheatPlanRequest {
pub crate_name: CrateName,
#[serde(default)]
pub version: Option<CrateVersion>,
pub features_json: FeaturesJson,
#[serde(default)]
pub target: Option<TargetTriple>,
#[serde(default)]
pub rustc_version: Option<WireRustcVersion>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct PreheatPlanResponse {
pub crate_name: CrateName,
pub version: CrateVersion,
pub rustc_version: WireRustcVersion,
pub targets: Vec<PreheatPlanTarget>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct PreheatPlanTarget {
pub target: TargetTriple,
pub root_cached: bool,
pub tasks: Vec<EnqueueRequest>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactInspection {
pub record: ArtifactRecord,
pub manifest: OciManifest,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct OciManifest {
pub schema_version: u32,
#[serde(default)]
pub media_type: Option<String>,
pub config: OciDescriptor,
#[serde(default)]
pub layers: Vec<OciDescriptor>,
#[serde(default)]
pub annotations: BTreeMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct OciDescriptor {
pub media_type: String,
pub digest: String,
pub size: u64,
#[serde(default)]
pub annotations: BTreeMap<String, String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactListQuery {
#[serde(default)]
pub rustc_version: Option<WireRustcVersion>,
#[serde(default)]
pub target: Option<TargetTriple>,
#[serde(default, rename = "crate", alias = "crate_name")]
pub crate_name: Option<CrateName>,
#[serde(default)]
pub limit: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactPruneRequest {
pub rustc_version: WireRustcVersion,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ArtifactPruneResponse {
pub deleted: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct ObserveRun {
pub task_id: String,
pub github_run_id: String,
}
#[cfg(test)]
mod tests {
use super::{CI_TARGET_TRIPLES, RunnerFamily, runner_family};
#[test]
fn runner_families_partition_ci_target_triples() {
let mut mapped: Vec<&str> = Vec::new();
for family in RunnerFamily::ALL {
mapped.extend_from_slice(family.targets());
}
mapped.sort_unstable();
let mut all = CI_TARGET_TRIPLES.to_vec();
all.sort_unstable();
assert_eq!(mapped, all);
for target in CI_TARGET_TRIPLES {
assert!(
runner_family(target).is_some(),
"{target} maps to no runner family"
);
}
assert_eq!(runner_family("aarch64-unknown-linux-musl"), None);
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct UsageStats {
pub daily_active_installs_7d: Option<u64>,
pub hits_24h: u64,
pub misses_24h: u64,
pub hit_rate_24h: f64,
pub cpu_hours_saved_30d: f64,
pub top_crates_30d: Vec<UsageStatEntry>,
pub targets_30d: Vec<UsageStatEntry>,
pub cli_versions_30d: Vec<UsageStatEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub struct UsageStatEntry {
pub name: String,
pub hits: u64,
}