summaryrefslogtreecommitdiffstats
path: root/src/env.rs
blob: 1708c061d8d73627de1e2be1b428965f70107a53 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use serde::Deserialize as _;
use std::os::unix::process::ExitStatusExt as _;

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum Env {
    V0(V0),
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct V0 {
    pipeline: Option<String>,
    idx: usize,
    #[serde(
        serialize_with = "serialize_status",
        deserialize_with = "deserialize_status"
    )]
    latest_status: async_std::process::ExitStatus,
    pwd: std::path::PathBuf,
}

impl Env {
    pub fn new() -> Self {
        Self::V0(V0 {
            pipeline: None,
            idx: 0,
            latest_status: std::process::ExitStatus::from_raw(0),
            pwd: std::env::current_dir().unwrap(),
        })
    }

    pub fn set_pipeline(&mut self, pipeline: String) {
        match self {
            Self::V0(env) => {
                env.pipeline = Some(pipeline);
            }
        }
    }

    pub fn idx(&self) -> usize {
        match self {
            Self::V0(env) => env.idx,
        }
    }

    pub fn set_idx(&mut self, idx: usize) {
        match self {
            Self::V0(env) => env.idx = idx,
        }
    }

    pub fn set_status(&mut self, status: async_std::process::ExitStatus) {
        match self {
            Self::V0(env) => {
                env.latest_status = status;
            }
        }
    }

    pub fn set_current_dir(&mut self, pwd: std::path::PathBuf) {
        match self {
            Self::V0(env) => {
                env.pwd = pwd;
            }
        }
    }

    pub fn current_dir(&self) -> &std::path::Path {
        match self {
            Self::V0(env) => &env.pwd,
        }
    }

    pub fn pipeline(&self) -> Option<&str> {
        match self {
            Self::V0(env) => env.pipeline.as_deref(),
        }
    }

    pub fn latest_status(&self) -> &async_std::process::ExitStatus {
        match self {
            Self::V0(env) => &env.latest_status,
        }
    }

    pub fn apply(&self, cmd: &mut pty_process::Command) {
        match self {
            Self::V0(env) => {
                cmd.current_dir(&env.pwd);
            }
        }
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    pub fn from_bytes(bytes: &[u8]) -> Self {
        bincode::deserialize(bytes).unwrap()
    }
}

#[allow(clippy::trivially_copy_pass_by_ref)]
fn serialize_status<S>(
    status: &std::process::ExitStatus,
    s: S,
) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    let code: u16 = status.code().unwrap_or(0).try_into().unwrap();
    let signal: u16 = status.signal().unwrap_or(0).try_into().unwrap();
    s.serialize_u16((code << 8) | signal)
}

fn deserialize_status<'de, D>(
    d: D,
) -> Result<std::process::ExitStatus, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let status = u16::deserialize(d)?;
    Ok(std::process::ExitStatus::from_raw(i32::from(status)))
}