weave/
header.rs

1//! Weave file information.
2//!
3//! The information about each weave file is stored in a header, as the first line of the file.
4
5use chrono::{DateTime, Utc};
6use serde_derive::{Deserialize, Serialize};
7use std::{collections::BTreeMap, io::Write};
8
9use crate::{Error, Result};
10
11/// The header placed at the beginning of the each weave file.  The deltas correspond with the
12/// deltas checked in.  Note that the value passed to [`crate::PullParser::new`] should be the `number`
13/// field of [`DeltaInfo`] and not the index in the `deltas` vec.
14#[derive(Clone, Serialize, Deserialize)]
15pub struct Header {
16    pub version: usize,
17    pub deltas: Vec<DeltaInfo>,
18}
19
20/// Information about a single delta.
21#[derive(Clone, Serialize, Deserialize)]
22pub struct DeltaInfo {
23    /// A tag giving the name for this particular delta.  Should be unique across all deltas.
24    pub name: String,
25    /// The delta number.  A unique integer that identifies this delta in the woven data below.
26    pub number: usize,
27    /// Arbitrary tags the user has asked to be stored with this delta.
28    pub tags: BTreeMap<String, String>,
29    /// A time stamp when this delta was added.
30    pub time: DateTime<Utc>,
31}
32
33const THIS_VERSION: usize = 1;
34
35impl Default for Header {
36    fn default() -> Header {
37        Header {
38            version: THIS_VERSION,
39            deltas: vec![],
40        }
41    }
42}
43
44impl Header {
45    /// Decode from the first line of the file.
46    pub fn decode(line: &str) -> Result<Header> {
47        if let Some(rest) = line.strip_prefix("\x01t") {
48            Ok(serde_json::from_str(rest)?)
49        } else {
50            // This probably comes from an sccs file.
51            Ok(Header {
52                version: 0,
53                deltas: vec![],
54            })
55        }
56    }
57
58    /// Add a delta to this header.  Returns the delta number to be used.
59    pub fn add(&mut self, mut tags: BTreeMap<String, String>) -> Result<usize> {
60        let name = if let Some(name) = tags.remove("name") {
61            name
62        } else {
63            return Err(Error::NameMissing);
64        };
65
66        let next_delta = self.deltas.iter().map(|x| x.number).max().unwrap_or(0) + 1;
67
68        self.deltas.push(DeltaInfo {
69            name,
70            number: next_delta,
71            tags,
72            time: Utc::now(),
73        });
74
75        Ok(next_delta)
76    }
77
78    /// Write the header to the writer, as the first line.
79    pub fn write<W: Write>(&self, mut wr: &mut W) -> Result<()> {
80        write!(&mut wr, "\x01t")?;
81        serde_json::to_writer(&mut wr, &self)?;
82        writeln!(&mut wr)?;
83        Ok(())
84    }
85}