Skip to main content

llama_server/
build.rs

1use crate::Error;
2use crate::http;
3
4use std::fmt;
5use std::io;
6use std::str::FromStr;
7
8const REPOSITORY: &str = "hecrj/llama-server";
9
10/// A specific build of `llama-server`.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Build(u32);
13
14impl Build {
15    /// Fetches the latest available [`Build`].
16    pub async fn latest() -> Result<Self, Error> {
17        use serde::Deserialize;
18
19        #[derive(Deserialize)]
20        struct Release {
21            tag_name: String,
22        }
23
24        let client = http::client();
25
26        let latest_release_url =
27            format!("https://api.github.com/repos/{REPOSITORY}/releases/latest");
28
29        let Release { tag_name } = client
30            .get(latest_release_url)
31            .send()
32            .await?
33            .error_for_status()?
34            .json()
35            .await?;
36
37        Ok(tag_name.parse()?)
38    }
39
40    /// Creates a new [`Build`] locked to the given number.
41    pub fn locked(number: u32) -> Self {
42        Self(number)
43    }
44
45    /// Returns the number of the [`Build`].
46    pub fn number(self) -> u32 {
47        self.0
48    }
49
50    pub(crate) fn url(self) -> String {
51        format!("https://github.com/{REPOSITORY}/releases/download/{self}")
52    }
53}
54
55impl FromStr for Build {
56    type Err = io::Error;
57
58    fn from_str(build: &str) -> Result<Self, Self::Err> {
59        if !build.starts_with('b') {
60            return Err(io::Error::other(format!("invalid build: {build}")));
61        }
62
63        build
64            .trim_start_matches('b')
65            .parse()
66            .map(Self)
67            .map_err(io::Error::other)
68    }
69}
70
71impl fmt::Display for Build {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        write!(f, "b{}", self.0)
74    }
75}