hglib/commands/
bookmarks.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use crate::client::{Client, HglibError, Runner};
6use crate::runcommand;
7
8pub struct Arg {}
9
10impl Default for Arg {
11    fn default() -> Self {
12        Self {}
13    }
14}
15
16impl Arg {
17    fn run(&self, client: &mut Client) -> Result<(Vec<u8>, i32), HglibError> {
18        runcommand!(client, "bookmarks", &[""])
19    }
20}
21
22#[derive(Debug, PartialEq)]
23pub struct Bookmark {
24    pub name: String,
25    pub rev: u64,
26    pub node: String,
27}
28
29#[derive(Debug, PartialEq)]
30pub struct Bookmarks {
31    pub bookmarks: Vec<Bookmark>,
32    pub current: Option<usize>,
33}
34
35impl Client {
36    pub fn bookmarks(&mut self, x: Arg) -> Result<Bookmarks, HglibError> {
37        let (data, _) = x.run(self)?;
38        let empty = b"no bookmarks set";
39        let mut bookmarks = Vec::new();
40        let mut current = None;
41
42        if data.starts_with(empty)
43            && data[empty.len()..]
44                .iter()
45                .all(|x| *x == b' ' || *x == b'\n')
46        {
47            return Ok(Bookmarks { bookmarks, current });
48        }
49
50        for line in data.split(|x| *x == b'\n').filter(|x| x.len() >= 3) {
51            let start = unsafe { line.get_unchecked(..3) };
52            if start.iter().any(|x| *x == b'*') {
53                current = Some(bookmarks.len());
54            }
55            let line = unsafe { line.get_unchecked(3..) };
56            let mut iter = line.split(|x| *x == b' ').filter(|x| !x.is_empty());
57            let name = String::from_utf8(iter.next().unwrap().to_vec())?;
58            let rev_node = iter.next().unwrap();
59            let iter = &mut rev_node.iter();
60            let rev = iter
61                .take_while(|x| **x != b':')
62                .fold(0, |r, x| r * 10 + u64::from(*x - b'0'));
63            let node = iter.as_slice();
64            let node = String::from_utf8(node.to_vec())?;
65            bookmarks.push(Bookmark { name, rev, node });
66        }
67
68        Ok(Bookmarks { bookmarks, current })
69    }
70}