1use std::path::Path;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{android::backend::AndroidBackend, apple::backend::AppleBackend, project::Project};
8
9#[derive(Debug, Serialize, Deserialize, Clone, Default)]
13pub struct Backends {
14 #[serde(default, skip_serializing_if = "String::is_empty")]
17 path: String,
18 android: Option<AndroidBackend>,
19 apple: Option<AppleBackend>,
20}
21
22impl Backends {
23 #[must_use]
25 pub const fn is_empty(&self) -> bool {
26 self.android.is_none() && self.apple.is_none()
27 }
28
29 #[must_use]
31 pub fn path(&self) -> &Path {
32 Path::new(&self.path)
33 }
34
35 pub fn set_path(&mut self, path: impl Into<String>) {
37 self.path = path.into();
38 }
39
40 #[must_use]
42 pub const fn android(&self) -> Option<&AndroidBackend> {
43 self.android.as_ref()
44 }
45
46 #[must_use]
48 pub const fn apple(&self) -> Option<&AppleBackend> {
49 self.apple.as_ref()
50 }
51
52 pub fn set_apple(&mut self, backend: AppleBackend) {
54 self.apple = Some(backend);
55 }
56
57 pub fn set_android(&mut self, backend: AndroidBackend) {
59 self.android = Some(backend);
60 }
61}
62
63#[derive(Debug, thiserror::Error)]
65pub enum FailToInitBackend {
66 #[error("Failed to write template files: {0}")]
68 Io(#[from] std::io::Error),
69}
70
71pub trait Backend: Sized + Send + Sync {
73 const DEFAULT_PATH: &'static str;
75
76 fn path(&self) -> &Path;
80
81 fn init(project: &Project) -> impl Future<Output = Result<Self, FailToInitBackend>> + Send;
86}