atom/
core.rs

1//! # Atom Core Types
2//!
3//! This module contains the fundamental types that represent atoms and their
4//! file system structure. These types form the foundation of the atom format
5//! and are used throughout the crate.
6
7use std::path::Path;
8
9use semver::Version;
10use serde::{Deserialize, Serialize};
11
12use super::id::AtomTag;
13
14#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
15/// Represents the deserialized form of an Atom, directly constructed from the TOML manifest.
16///
17/// This struct contains the basic metadata of an Atom but lacks the context-specific
18/// [`crate::AtomId`], which must be constructed separately.
19#[serde(deny_unknown_fields)]
20pub struct Atom {
21    /// The verified, human-readable Unicode identifier for the Atom.
22    pub tag: AtomTag,
23
24    /// The version of the Atom.
25    pub version: Version,
26
27    #[serde(skip_serializing_if = "Option::is_none")]
28    /// An optional description of the Atom.
29    pub description: Option<String>,
30}
31
32#[derive(Debug)]
33/// Represents the file system paths associated with an atom.
34///
35/// This struct manages the relationship between an atom's manifest file
36/// (the "spec") and its content directory. It handles the logic for determining
37/// these paths based on whether we're given a manifest file or a content directory.
38pub(crate) struct AtomPaths<P>
39where
40    P: AsRef<Path>,
41{
42    /// Path to the atom's manifest file (atom.toml)
43    spec: P,
44    /// Path to the atom's content directory
45    content: P,
46}
47
48use std::path::PathBuf;
49impl AtomPaths<PathBuf> {
50    /// Creates a new `AtomPaths` instance from a given path.
51    ///
52    /// If the path points to a manifest file (named `atom.toml`), then:
53    /// - `spec` is set to that file path
54    /// - `content` is set to the parent directory
55    ///
56    /// If the path points to a directory, then:
57    /// - `spec` is set to `path/atom.toml`
58    /// - `content` is set to the provided path
59    ///
60    /// # Arguments
61    ///
62    /// * `path` - Either a path to a manifest file or content directory
63    ///
64    /// # Returns
65    ///
66    /// An `AtomPaths` instance with the appropriate spec and content paths.
67    pub(crate) fn new<P: AsRef<Path>>(path: P) -> Self {
68        let path = path.as_ref();
69        let name = path
70            .file_name()
71            .unwrap_or(path.as_os_str())
72            .to_string_lossy();
73
74        if name == crate::MANIFEST_NAME.as_str() {
75            AtomPaths {
76                spec: path.into(),
77                content: path.parent().unwrap_or(Path::new("")).into(),
78            }
79        } else {
80            let spec = path.join(crate::MANIFEST_NAME.as_str());
81            AtomPaths {
82                spec: spec.clone(),
83                content: path.into(),
84            }
85        }
86    }
87
88    /// Returns the path to the atom's manifest file.
89    ///
90    /// This is the `atom.toml` file that contains the atom's metadata
91    /// and dependency specifications.
92    pub fn spec(&self) -> &Path {
93        self.spec.as_ref()
94    }
95
96    /// Returns the path to the atom's content directory.
97    ///
98    /// This directory contains the actual source code or files that
99    /// make up the atom's content.
100    pub fn content(&self) -> &Path {
101        self.content.as_ref()
102    }
103}