annotate rust/hg-core/src/revlog/changelog.rs @ 52156:039b7caeb4d9

rust-revlog: introduce an `options` module This helps group all the relevant revlog options code and makes the `mod.rs` more readable.
author Rapha?l Gom?s <rgomes@octobus.net>
date Wed, 25 Sep 2024 18:24:15 +0200
parents 1d6982827c4b
children e01e84e5e426
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
1 use std::ascii::escape_default;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
2 use std::borrow::Cow;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
3 use std::collections::BTreeMap;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
4 use std::fmt::{Debug, Formatter};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
5 use std::{iter, str};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
6
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
7 use chrono::{DateTime, FixedOffset, Utc};
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
8 use itertools::{Either, Itertools};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
9
46443
43d63979a75e rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents: 46433
diff changeset
10 use crate::errors::HgError;
51721
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51703
diff changeset
11 use crate::revlog::Index;
50744
9865af7191d2 rust-changelog: removed now useless early conditional for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50743
diff changeset
12 use crate::revlog::Revision;
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
13 use crate::revlog::{Node, NodePrefix};
49937
750409505286 rust-clippy: merge "revlog" module definition and struct implementation
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49930
diff changeset
14 use crate::revlog::{Revlog, RevlogEntry, RevlogError};
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
15 use crate::utils::hg_path::HgPath;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
16 use crate::vfs::VfsImpl;
52156
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
17 use crate::{Graph, GraphError, UncheckedRevision};
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
18
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
19 use super::options::RevlogOpenOptions;
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
20
50406
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
21 /// A specialized `Revlog` to work with changelog data format.
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
22 pub struct Changelog {
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
23 /// The generic `revlog` format.
46433
4b381dbbf8b7 rhg: centralize parsing of `--rev` CLI arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46431
diff changeset
24 pub(crate) revlog: Revlog,
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
25 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
26
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
27 impl Changelog {
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
28 /// Open the `changelog` of a repository given by its root.
51188
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50975
diff changeset
29 pub fn open(
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
30 store_vfs: &VfsImpl,
51188
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50975
diff changeset
31 options: RevlogOpenOptions,
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50975
diff changeset
32 ) -> Result<Self, HgError> {
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50975
diff changeset
33 let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?;
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
34 Ok(Self { revlog })
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
35 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
36
50406
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
37 /// Return the `ChangelogRevisionData` for the given node ID.
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47968
diff changeset
38 pub fn data_for_node(
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
39 &self,
46431
645ee7225fab rust: Make NodePrefix allocation-free and Copy, remove NodePrefixRef
Simon Sapin <simon.sapin@octobus.net>
parents: 46167
diff changeset
40 node: NodePrefix,
48540
20d0d896183e rhg: Rename some revlog-related types and methods
Simon Sapin <simon.sapin@octobus.net>
parents: 48198
diff changeset
41 ) -> Result<ChangelogRevisionData, RevlogError> {
47968
6f579618ea7b rust: Rename the `Revlog::get_node_rev` method to `rev_from_node`
Simon Sapin <simon.sapin@octobus.net>
parents: 47967
diff changeset
42 let rev = self.revlog.rev_from_node(node)?;
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
43 self.entry_for_checked_rev(rev)?.data()
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
44 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
45
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
46 /// Return the [`ChangelogEntry`] for the given revision number.
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
47 pub fn entry_for_rev(
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
48 &self,
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
49 rev: UncheckedRevision,
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
50 ) -> Result<ChangelogEntry, RevlogError> {
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
51 let revlog_entry = self.revlog.get_entry(rev)?;
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
52 Ok(ChangelogEntry { revlog_entry })
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
53 }
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
54
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
55 /// Same as [`Self::entry_for_rev`] for checked revisions.
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
56 fn entry_for_checked_rev(
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
57 &self,
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
58 rev: Revision,
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
59 ) -> Result<ChangelogEntry, RevlogError> {
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
60 let revlog_entry = self.revlog.get_entry_for_checked_rev(rev)?;
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
61 Ok(ChangelogEntry { revlog_entry })
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
62 }
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
63
50406
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
64 /// Return the [`ChangelogRevisionData`] for the given revision number.
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
65 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
66 /// This is a useful shortcut in case the caller does not need the
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
67 /// generic revlog information (parents, hashes etc). Otherwise
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
68 /// consider taking a [`ChangelogEntry`] with
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
69 /// [entry_for_rev](`Self::entry_for_rev`) and doing everything from there.
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47968
diff changeset
70 pub fn data_for_rev(
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
71 &self,
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
72 rev: UncheckedRevision,
48540
20d0d896183e rhg: Rename some revlog-related types and methods
Simon Sapin <simon.sapin@octobus.net>
parents: 48198
diff changeset
73 ) -> Result<ChangelogRevisionData, RevlogError> {
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
74 self.entry_for_rev(rev)?.data()
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
75 }
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
76
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
77 pub fn node_from_rev(&self, rev: UncheckedRevision) -> Option<&Node> {
47967
6c653d9d41b8 rust: Make private the `index` field of the `Revlog` struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
78 self.revlog.node_from_rev(rev)
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
79 }
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
80
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
81 pub fn rev_from_node(
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
82 &self,
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
83 node: NodePrefix,
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
84 ) -> Result<Revision, RevlogError> {
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
85 self.revlog.rev_from_node(node)
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
86 }
51721
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51703
diff changeset
87
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51703
diff changeset
88 pub fn get_index(&self) -> &Index {
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51703
diff changeset
89 &self.revlog.index
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51703
diff changeset
90 }
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
91 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
92
50975
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
93 impl Graph for Changelog {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
94 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
95 self.revlog.parents(rev)
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
96 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
97 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50974
diff changeset
98
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
99 /// A specialized `RevlogEntry` for `changelog` data format
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
100 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
101 /// This is a `RevlogEntry` with the added semantics that the associated
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
102 /// data should meet the requirements for `changelog`, materialized by
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
103 /// the fact that `data()` constructs a `ChangelogRevisionData`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
104 /// In case that promise would be broken, the `data` method returns an error.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
105 #[derive(Clone)]
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
106 pub struct ChangelogEntry<'changelog> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
107 /// Same data, as a generic `RevlogEntry`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
108 pub(crate) revlog_entry: RevlogEntry<'changelog>,
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
109 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
110
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
111 impl<'changelog> ChangelogEntry<'changelog> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
112 pub fn data<'a>(
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
113 &'a self,
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
114 ) -> Result<ChangelogRevisionData<'changelog>, RevlogError> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
115 let bytes = self.revlog_entry.data()?;
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
116 if bytes.is_empty() {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
117 Ok(ChangelogRevisionData::null())
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
118 } else {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
119 Ok(ChangelogRevisionData::new(bytes).map_err(|err| {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
120 RevlogError::Other(HgError::CorruptedRepository(format!(
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
121 "Invalid changelog data for revision {}: {:?}",
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
122 self.revlog_entry.revision(),
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
123 err
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
124 )))
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
125 })?)
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
126 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
127 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
128
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
129 /// Obtain a reference to the underlying `RevlogEntry`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
130 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
131 /// This allows the caller to access the information that is common
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
132 /// to all revlog entries: revision number, node id, parent revisions etc.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
133 pub fn as_revlog_entry(&self) -> &RevlogEntry {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
134 &self.revlog_entry
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
135 }
50411
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
136
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
137 pub fn p1_entry(&self) -> Result<Option<ChangelogEntry>, RevlogError> {
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
138 Ok(self
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
139 .revlog_entry
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
140 .p1_entry()?
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
141 .map(|revlog_entry| Self { revlog_entry }))
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
142 }
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
143
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
144 pub fn p2_entry(&self) -> Result<Option<ChangelogEntry>, RevlogError> {
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
145 Ok(self
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
146 .revlog_entry
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
147 .p2_entry()?
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
148 .map(|revlog_entry| Self { revlog_entry }))
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50408
diff changeset
149 }
50408
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
150 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50407
diff changeset
151
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
152 /// `Changelog` entry which knows how to interpret the `changelog` data bytes.
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
153 #[derive(PartialEq)]
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
154 pub struct ChangelogRevisionData<'changelog> {
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
155 /// The data bytes of the `changelog` entry.
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
156 bytes: Cow<'changelog, [u8]>,
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
157 /// The end offset for the hex manifest (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
158 manifest_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
159 /// The end offset for the user+email (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
160 user_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
161 /// The end offset for the timestamp+timezone+extras (not including the
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
162 /// newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
163 timestamp_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
164 /// The end offset for the file list (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
165 files_end: usize,
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
166 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
167
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
168 impl<'changelog> ChangelogRevisionData<'changelog> {
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
169 fn new(bytes: Cow<'changelog, [u8]>) -> Result<Self, HgError> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
170 let mut line_iter = bytes.split(|b| b == &b'\n');
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
171 let manifest_end = line_iter
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
172 .next()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
173 .expect("Empty iterator from split()?")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
174 .len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
175 let user_slice = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
176 HgError::corrupted("Changeset data truncated after manifest line")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
177 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
178 let user_end = manifest_end + 1 + user_slice.len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
179 let timestamp_slice = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
180 HgError::corrupted("Changeset data truncated after user line")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
181 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
182 let timestamp_end = user_end + 1 + timestamp_slice.len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
183 let mut files_end = timestamp_end + 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
184 loop {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
185 let line = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
186 HgError::corrupted("Changeset data truncated in files list")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
187 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
188 if line.is_empty() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
189 if files_end == bytes.len() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
190 // The list of files ended with a single newline (there
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
191 // should be two)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
192 return Err(HgError::corrupted(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
193 "Changeset data truncated after files list",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
194 ));
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
195 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
196 files_end -= 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
197 break;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
198 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
199 files_end += line.len() + 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
200 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
201
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
202 Ok(Self {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
203 bytes,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
204 manifest_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
205 user_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
206 timestamp_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
207 files_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
208 })
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
209 }
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
210
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
211 fn null() -> Self {
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
212 Self::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
213 b"0000000000000000000000000000000000000000\n\n0 0\n\n",
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
214 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
215 .unwrap()
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
216 }
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
217
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
218 /// Return an iterator over the lines of the entry.
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
219 pub fn lines(&self) -> impl Iterator<Item = &[u8]> {
49062
fb82b5cb8301 rust-changelog: don't skip empty lines when iterating over changeset lines
Martin von Zweigbergk <martinvonz@google.com>
parents: 48541
diff changeset
220 self.bytes.split(|b| b == &b'\n')
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
221 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
222
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
223 /// Return the node id of the `manifest` referenced by this `changelog`
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
224 /// entry.
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
225 pub fn manifest_node(&self) -> Result<Node, HgError> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
226 let manifest_node_hex = &self.bytes[..self.manifest_end];
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
227 Node::from_hex_for_repo(manifest_node_hex)
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
228 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
229
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
230 /// The full user string (usually a name followed by an email enclosed in
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
231 /// angle brackets)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
232 pub fn user(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
233 &self.bytes[self.manifest_end + 1..self.user_end]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
234 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
235
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
236 /// The full timestamp line (timestamp in seconds, offset in seconds, and
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
237 /// possibly extras)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
238 // TODO: We should expose this in a more useful way
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
239 pub fn timestamp_line(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
240 &self.bytes[self.user_end + 1..self.timestamp_end]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
241 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
242
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
243 /// Parsed timestamp.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
244 pub fn timestamp(&self) -> Result<DateTime<FixedOffset>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
245 parse_timestamp(self.timestamp_line())
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
246 }
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
247
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
248 /// Optional commit extras.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
249 pub fn extra(&self) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
250 parse_timestamp_line_extra(self.timestamp_line())
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
251 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
252
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
253 /// The files changed in this revision.
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
254 pub fn files(&self) -> impl Iterator<Item = &HgPath> {
51360
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
255 if self.timestamp_end == self.files_end {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
256 Either::Left(iter::empty())
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
257 } else {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
258 Either::Right(
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
259 self.bytes[self.timestamp_end + 1..self.files_end]
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
260 .split(|b| b == &b'\n')
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
261 .map(HgPath::new),
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
262 )
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
263 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
264 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
265
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
266 /// The change description.
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
267 pub fn description(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
268 &self.bytes[self.files_end + 2..]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
269 }
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
270 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
271
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
272 impl Debug for ChangelogRevisionData<'_> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
273 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
274 f.debug_struct("ChangelogRevisionData")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
275 .field("bytes", &debug_bytes(&self.bytes))
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
276 .field("manifest", &debug_bytes(&self.bytes[..self.manifest_end]))
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
277 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
278 "user",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
279 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
280 &self.bytes[self.manifest_end + 1..self.user_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
281 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
282 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
283 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
284 "timestamp",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
285 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
286 &self.bytes[self.user_end + 1..self.timestamp_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
287 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
288 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
289 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
290 "files",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
291 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
292 &self.bytes[self.timestamp_end + 1..self.files_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
293 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
294 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
295 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
296 "description",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
297 &debug_bytes(&self.bytes[self.files_end + 2..]),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
298 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
299 .finish()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
300 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
301 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
302
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
303 fn debug_bytes(bytes: &[u8]) -> String {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
304 String::from_utf8_lossy(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
305 &bytes.iter().flat_map(|b| escape_default(*b)).collect_vec(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
306 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
307 .to_string()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
308 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
309
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
310 /// Parse the raw bytes of the timestamp line from a changelog entry.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
311 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
312 /// According to the documentation in `hg help dates` and the
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
313 /// implementation in `changelog.py`, the format of the timestamp line
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
314 /// is `time tz extra\n` where:
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
315 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
316 /// - `time` is an ASCII-encoded signed int or float denoting a UTC timestamp
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
317 /// as seconds since the UNIX epoch.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
318 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
319 /// - `tz` is the timezone offset as an ASCII-encoded signed integer denoting
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
320 /// seconds WEST of UTC (so negative for timezones east of UTC, which is the
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
321 /// opposite of the sign in ISO 8601 timestamps).
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
322 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
323 /// - `extra` is an optional set of NUL-delimited key-value pairs, with the key
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
324 /// and value in each pair separated by an ASCII colon. Keys are limited to
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
325 /// ASCII letters, digits, hyphens, and underscores, whereas values can be
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
326 /// arbitrary bytes.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
327 fn parse_timestamp(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
328 timestamp_line: &[u8],
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
329 ) -> Result<DateTime<FixedOffset>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
330 let mut parts = timestamp_line.splitn(3, |c| *c == b' ');
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
331
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
332 let timestamp_bytes = parts
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
333 .next()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
334 .ok_or_else(|| HgError::corrupted("missing timestamp"))?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
335 let timestamp_str = str::from_utf8(timestamp_bytes).map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
336 HgError::corrupted(format!("timestamp is not valid UTF-8: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
337 })?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
338 let timestamp_utc = timestamp_str
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
339 .parse()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
340 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
341 HgError::corrupted(format!("failed to parse timestamp: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
342 })
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
343 .and_then(|secs| {
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
344 DateTime::from_timestamp(secs, 0).ok_or_else(|| {
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
345 HgError::corrupted(format!(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
346 "integer timestamp out of valid range: {secs}"
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
347 ))
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
348 })
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
349 })
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
350 // Attempt to parse the timestamp as a float if we can't parse
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
351 // it as an int. It doesn't seem like float timestamps are actually
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
352 // used in practice, but the Python code supports them.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
353 .or_else(|_| parse_float_timestamp(timestamp_str))?;
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
354
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
355 let timezone_bytes = parts
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
356 .next()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
357 .ok_or_else(|| HgError::corrupted("missing timezone"))?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
358 let timezone_secs: i32 = str::from_utf8(timezone_bytes)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
359 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
360 HgError::corrupted(format!("timezone is not valid UTF-8: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
361 })?
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
362 .parse()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
363 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
364 HgError::corrupted(format!("timezone is not an integer: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
365 })?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
366 let timezone = FixedOffset::west_opt(timezone_secs)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
367 .ok_or_else(|| HgError::corrupted("timezone offset out of bounds"))?;
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
368
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
369 Ok(DateTime::from_naive_utc_and_offset(
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
370 timestamp_utc.naive_utc(),
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
371 timezone,
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
372 ))
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
373 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
374
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
375 /// Attempt to parse the given string as floating-point timestamp, and
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
376 /// convert the result into a `chrono::NaiveDateTime`.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
377 fn parse_float_timestamp(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
378 timestamp_str: &str,
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
379 ) -> Result<DateTime<Utc>, HgError> {
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
380 let timestamp = timestamp_str.parse::<f64>().map_err(|e| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
381 HgError::corrupted(format!("failed to parse timestamp: {e}"))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
382 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
383
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
384 // To construct a `NaiveDateTime` we'll need to convert the float
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
385 // into signed integer seconds and unsigned integer nanoseconds.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
386 let mut secs = timestamp.trunc() as i64;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
387 let mut subsecs = timestamp.fract();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
389 // If the timestamp is negative, we need to express the fractional
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
390 // component as positive nanoseconds since the previous second.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
391 if timestamp < 0.0 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
392 secs -= 1;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
393 subsecs += 1.0;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
394 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
395
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
396 // This cast should be safe because the fractional component is
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
397 // by definition less than 1.0, so this value should not exceed
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
398 // 1 billion, which is representable as an f64 without loss of
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
399 // precision and should fit into a u32 without overflowing.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
400 //
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
401 // (Any loss of precision in the fractional component will have
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
402 // already happened at the time of initial parsing; in general,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
403 // f64s are insufficiently precise to provide nanosecond-level
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
404 // precision with present-day timestamps.)
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
405 let nsecs = (subsecs * 1_000_000_000.0) as u32;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
406
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
407 DateTime::from_timestamp(secs, nsecs).ok_or_else(|| {
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
408 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
409 "float timestamp out of valid range: {timestamp}"
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
410 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
411 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
412 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
413
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
414 /// Decode changeset extra fields.
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
415 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
416 /// Extras are null-delimited key-value pairs where the key consists of ASCII
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
417 /// alphanumeric characters plus hyphens and underscores, and the value can
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
418 /// contain arbitrary bytes.
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
419 fn decode_extra(extra: &[u8]) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
420 extra
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
421 .split(|c| *c == b'\0')
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
422 .map(|pair| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
423 let pair = unescape_extra(pair);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
424 let mut iter = pair.splitn(2, |c| *c == b':');
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
425
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
426 let key_bytes =
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
427 iter.next().filter(|k| !k.is_empty()).ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
428 HgError::corrupted("empty key in changeset extras")
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
429 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
430
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
431 let key = str::from_utf8(key_bytes)
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
432 .ok()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
433 .filter(|k| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
434 k.chars().all(|c| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
435 c.is_ascii_alphanumeric() || c == '_' || c == '-'
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
436 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
437 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
438 .ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
439 let key = String::from_utf8_lossy(key_bytes);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
440 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
441 "invalid key in changeset extras: {key}",
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
442 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
443 })?
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
444 .to_string();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
445
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
446 let value = iter.next().map(Into::into).ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
447 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
448 "missing value for changeset extra: {key}"
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
449 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
450 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
451
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
452 Ok((key, value))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
453 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
454 .collect()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
455 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
456
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
457 /// Parse the extra fields from a changeset's timestamp line.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
458 fn parse_timestamp_line_extra(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
459 timestamp_line: &[u8],
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
460 ) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
461 Ok(timestamp_line
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
462 .splitn(3, |c| *c == b' ')
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
463 .nth(2)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
464 .map(decode_extra)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
465 .transpose()?
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
466 .unwrap_or_default())
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
467 }
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
468
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
469 /// Decode Mercurial's escaping for changelog extras.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
470 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
471 /// The `_string_escape` function in `changelog.py` only escapes 4 characters
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
472 /// (null, backslash, newline, and carriage return) so we only decode those.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
473 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
474 /// The Python code also includes a workaround for decoding escaped nuls
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
475 /// that are followed by an ASCII octal digit, since Python's built-in
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
476 /// `string_escape` codec will interpret that as an escaped octal byte value.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
477 /// That workaround is omitted here since we don't support decoding octal.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
478 fn unescape_extra(bytes: &[u8]) -> Vec<u8> {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
479 let mut output = Vec::with_capacity(bytes.len());
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
480 let mut input = bytes.iter().copied();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
481
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
482 while let Some(c) = input.next() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
483 if c != b'\\' {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
484 output.push(c);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
485 continue;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
486 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
487
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
488 match input.next() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
489 Some(b'0') => output.push(b'\0'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
490 Some(b'\\') => output.push(b'\\'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
491 Some(b'n') => output.push(b'\n'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
492 Some(b'r') => output.push(b'\r'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
493 // The following cases should never occur in theory because any
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
494 // backslashes in the original input should have been escaped
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
495 // with another backslash, so it should not be possible to
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
496 // observe an escape sequence other than the 4 above.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
497 Some(c) => output.extend_from_slice(&[b'\\', c]),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
498 None => output.push(b'\\'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
499 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
500 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
501
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
502 output
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
503 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
504
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
505 #[cfg(test)]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
506 mod tests {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
507 use super::*;
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
508 use crate::vfs::VfsImpl;
52156
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
509 use crate::NULL_REVISION;
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
510 use pretty_assertions::assert_eq;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
511
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
512 #[test]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
513 fn test_create_changelogrevisiondata_invalid() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
514 // Completely empty
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
515 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
516 // No newline after manifest
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
517 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
518 // No newline after user
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
519 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd\n")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
520 // No newline after timestamp
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
521 assert!(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
522 ChangelogRevisionData::new(Cow::Borrowed(b"abcd\n\n0 0")).is_err()
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
523 );
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
524 // Missing newline after files
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
525 assert!(ChangelogRevisionData::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
526 b"abcd\n\n0 0\nfile1\nfile2"
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
527 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
528 .is_err(),);
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
529 // Only one newline after files
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
530 assert!(ChangelogRevisionData::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
531 b"abcd\n\n0 0\nfile1\nfile2\n"
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
532 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
533 .is_err(),);
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
534 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
535
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
536 #[test]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
537 fn test_create_changelogrevisiondata() {
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
538 let data = ChangelogRevisionData::new(Cow::Borrowed(
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
539 b"0123456789abcdef0123456789abcdef01234567
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
540 Some One <someone@example.com>
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
541 0 0
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
542 file1
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
543 file2
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
544
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
545 some
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
546 commit
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
547 message",
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
548 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
549 .unwrap();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
550 assert_eq!(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
551 data.manifest_node().unwrap(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
552 Node::from_hex("0123456789abcdef0123456789abcdef01234567")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
553 .unwrap()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
554 );
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
555 assert_eq!(data.user(), b"Some One <someone@example.com>");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
556 assert_eq!(data.timestamp_line(), b"0 0");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
557 assert_eq!(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
558 data.files().collect_vec(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
559 vec![HgPath::new("file1"), HgPath::new("file2")]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
560 );
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
561 assert_eq!(data.description(), b"some\ncommit\nmessage");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
562 }
50407
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
563
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
564 #[test]
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
565 fn test_data_from_rev_null() -> Result<(), RevlogError> {
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
566 // an empty revlog will be enough for this case
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
567 let temp = tempfile::tempdir().unwrap();
51864
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
568 let vfs = VfsImpl {
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
569 base: temp.path().to_owned(),
db7dbe6f7bb2 rust: add Vfs trait
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51863
diff changeset
570 };
50407
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
571 std::fs::write(temp.path().join("foo.i"), b"").unwrap();
51863
69b804c8e09e rust: use new revlog configs in all revlog opening code
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51721
diff changeset
572 std::fs::write(temp.path().join("foo.d"), b"").unwrap();
52156
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
573 let revlog =
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
574 Revlog::open(&vfs, "foo.i", None, RevlogOpenOptions::default())
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51913
diff changeset
575 .unwrap();
50407
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
576
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
577 let changelog = Changelog { revlog };
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
578 assert_eq!(
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
579 changelog.data_for_rev(NULL_REVISION.into())?,
50407
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
580 ChangelogRevisionData::null()
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
581 );
50743
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
582 // same with the intermediate entry object
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
583 assert_eq!(
50974
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Rapha?l Gom?s <rgomes@octobus.net>
parents: 50744
diff changeset
584 changelog.entry_for_rev(NULL_REVISION.into())?.data()?,
50743
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
585 ChangelogRevisionData::null()
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
586 );
50407
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
587 Ok(())
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50406
diff changeset
588 }
51360
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
589
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
590 #[test]
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
591 fn test_empty_files_list() {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
592 assert!(ChangelogRevisionData::null()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
593 .files()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
594 .collect_vec()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
595 .is_empty());
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50975
diff changeset
596 }
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
597
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
598 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
599 fn test_unescape_basic() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
600 // '\0', '\\', '\n', and '\r' are correctly unescaped.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
601 let expected = b"AAA\0BBB\\CCC\nDDD\rEEE";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
602 let escaped = br"AAA\0BBB\\CCC\nDDD\rEEE";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
603 let unescaped = unescape_extra(escaped);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
604 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
605 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
606
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
607 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
608 fn test_unescape_unsupported_sequence() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
609 // Other escape sequences are left unaltered.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
610 for c in 0u8..255 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
611 match c {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
612 b'0' | b'\\' | b'n' | b'r' => continue,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
613 c => {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
614 let expected = &[b'\\', c][..];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
615 let unescaped = unescape_extra(expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
616 assert_eq!(expected, &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
617 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
618 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
619 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
620 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
621
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
622 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
623 fn test_unescape_trailing_backslash() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
624 // Trailing backslashes are OK.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
625 let expected = br"hi\";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
626 let unescaped = unescape_extra(expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
627 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
628 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
629
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
630 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
631 fn test_unescape_nul_followed_by_octal() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
632 // Escaped NUL chars followed by octal digits are decoded correctly.
51703
ec7171748350 rust: apply clippy lints
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51696
diff changeset
633 let expected = b"\x0012";
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
634 let escaped = br"\012";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
635 let unescaped = unescape_extra(escaped);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
636 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
637 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
638
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
639 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
640 fn test_parse_float_timestamp() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
641 let test_cases = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
642 // Zero should map to the UNIX epoch.
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
643 ("0.0", "1970-01-01 00:00:00 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
644 // Negative zero should be the same as positive zero.
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
645 ("-0.0", "1970-01-01 00:00:00 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
646 // Values without fractional components should work like integers.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
647 // (Assuming the timestamp is within the limits of f64 precision.)
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
648 ("1115154970.0", "2005-05-03 21:16:10 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
649 // We expect some loss of precision in the fractional component
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
650 // when parsing arbitrary floating-point values.
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
651 ("1115154970.123456789", "2005-05-03 21:16:10.123456716 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
652 // But representable f64 values should parse losslessly.
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
653 ("1115154970.123456716", "2005-05-03 21:16:10.123456716 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
654 // Negative fractional components are subtracted from the epoch.
51913
1d6982827c4b rust: fix the deprecation warning in NaiveDateTime::from_timestamp
Arseniy Alekseyev <aalekseyev@janestreet.com>
parents: 51864
diff changeset
655 ("-1.333", "1969-12-31 23:59:58.667 UTC"),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
656 ];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
657
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
658 for (input, expected) in test_cases {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
659 let res = parse_float_timestamp(input).unwrap().to_string();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
660 assert_eq!(res, expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
661 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
662 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
663
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
664 fn escape_extra(bytes: &[u8]) -> Vec<u8> {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
665 let mut output = Vec::with_capacity(bytes.len());
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
666
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
667 for c in bytes.iter().copied() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
668 output.extend_from_slice(match c {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
669 b'\0' => &b"\\0"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
670 b'\\' => &b"\\\\"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
671 b'\n' => &b"\\n"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
672 b'\r' => &b"\\r"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
673 _ => {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
674 output.push(c);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
675 continue;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
676 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
677 });
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
678 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
679
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
680 output
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
681 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
682
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
683 fn encode_extra<K, V>(pairs: impl IntoIterator<Item = (K, V)>) -> Vec<u8>
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
684 where
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
685 K: AsRef<[u8]>,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
686 V: AsRef<[u8]>,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
687 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
688 let extras = pairs.into_iter().map(|(k, v)| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
689 escape_extra(&[k.as_ref(), b":", v.as_ref()].concat())
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
690 });
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
691 // Use fully-qualified syntax to avoid a future naming conflict with
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
692 // the standard library: https://github.com/rust-lang/rust/issues/79524
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
693 Itertools::intersperse(extras, b"\0".to_vec()).concat()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
694 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
695
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
696 #[test]
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
697 fn test_decode_extra() {
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
698 let extra = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
699 ("branch".into(), b"default".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
700 ("key-with-hyphens".into(), b"value1".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
701 ("key_with_underscores".into(), b"value2".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
702 ("empty-value".into(), b"".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
703 ("binary-value".into(), (0u8..=255).collect::<Vec<_>>()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
704 ]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
705 .into_iter()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
706 .collect::<BTreeMap<String, Vec<u8>>>();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
707
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
708 let encoded = encode_extra(&extra);
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
709 let decoded = decode_extra(&encoded).unwrap();
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
710
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
711 assert_eq!(extra, decoded);
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
712 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
713
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
714 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
715 fn test_corrupt_extra() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
716 let test_cases = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
717 (&b""[..], "empty input"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
718 (&b"\0"[..], "unexpected null byte"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
719 (&b":empty-key"[..], "empty key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
720 (&b"\0leading-null:"[..], "leading null"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
721 (&b"trailing-null:\0"[..], "trailing null"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
722 (&b"missing-value"[..], "missing value"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
723 (&b"$!@# non-alphanum-key:"[..], "non-alphanumeric key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
724 (&b"\xF0\x9F\xA6\x80 non-ascii-key:"[..], "non-ASCII key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
725 ];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
726
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
727 for (extra, msg) in test_cases {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
728 assert!(
51703
ec7171748350 rust: apply clippy lints
Rapha?l Gom?s <rgomes@octobus.net>
parents: 51696
diff changeset
729 decode_extra(extra).is_err(),
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
730 "corrupt extra should have failed to parse: {}",
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
731 msg
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
732 );
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
733 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
734 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
735
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
736 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
737 fn test_parse_timestamp_line() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
738 let extra = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
739 ("branch".into(), b"default".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
740 ("key-with-hyphens".into(), b"value1".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
741 ("key_with_underscores".into(), b"value2".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
742 ("empty-value".into(), b"".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
743 ("binary-value".into(), (0u8..=255).collect::<Vec<_>>()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
744 ]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
745 .into_iter()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
746 .collect::<BTreeMap<String, Vec<u8>>>();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
747
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
748 let mut line: Vec<u8> = b"1115154970 28800 ".to_vec();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
749 line.extend_from_slice(&encode_extra(&extra));
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
750
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
751 let timestamp = parse_timestamp(&line).unwrap();
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
752 assert_eq!(&timestamp.to_rfc3339(), "2005-05-03T13:16:10-08:00");
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
753
51390
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
754 let parsed_extra = parse_timestamp_line_extra(&line).unwrap();
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51388
diff changeset
755 assert_eq!(extra, parsed_extra);
51388
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51366
diff changeset
756 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
757 }