quest_cli/
types.rs

1use std::{
2    fs,
3    path::{Path, PathBuf},
4    str::FromStr,
5};
6
7use anyhow::{Context, Result};
8use serde::Deserialize;
9
10#[derive(Debug, Clone, Deserialize)]
11#[serde(from = "String")]
12pub enum StringOrFile {
13    String(String),
14    File(PathBuf),
15}
16
17impl StringOrFile {
18    pub fn resolve(&self) -> Result<Vec<u8>> {
19        match self {
20            StringOrFile::String(s) => Ok(s.as_bytes().to_vec()),
21            StringOrFile::File(path) => {
22                fs::read(path).with_context(|| format!("Failed to read file: {}", path.display()))
23            }
24        }
25    }
26
27    pub fn as_str(&self) -> Option<&str> {
28        match self {
29            StringOrFile::String(s) => Some(s),
30            StringOrFile::File(_) => None,
31        }
32    }
33
34    pub fn as_path(&self) -> Option<&Path> {
35        match self {
36            StringOrFile::String(_) => None,
37            StringOrFile::File(path) => Some(path),
38        }
39    }
40}
41
42impl FromStr for StringOrFile {
43    type Err = std::convert::Infallible;
44
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        if let Some(path) = s.strip_prefix('@') {
47            Ok(StringOrFile::File(PathBuf::from(path)))
48        } else {
49            Ok(StringOrFile::String(s.to_string()))
50        }
51    }
52}
53
54impl From<String> for StringOrFile {
55    fn from(s: String) -> Self {
56        StringOrFile::from_str(&s).unwrap()
57    }
58}
59
60#[derive(Debug, Clone, Deserialize)]
61#[serde(from = "String")]
62pub struct FormField {
63    pub name: String,
64    pub value: StringOrFile,
65}
66
67impl FromStr for FormField {
68    type Err = String;
69
70    fn from_str(s: &str) -> Result<Self, Self::Err> {
71        let (name, value) = s
72            .split_once('=')
73            .ok_or_else(|| format!("Invalid form field format: '{}'. Expected 'key=value'", s))?;
74
75        let value = StringOrFile::from_str(value)
76            .map_err(|e| format!("Failed to parse form field value: {}", e))?;
77
78        Ok(FormField {
79            name: name.to_string(),
80            value,
81        })
82    }
83}
84
85impl From<String> for FormField {
86    fn from(s: String) -> Self {
87        FormField::from_str(&s).unwrap()
88    }
89}