view rust/hg-core/src/revset.rs @ 47123:d8ac62374943

dirstate-tree: Make `DirstateMap` borrow from a bytes buffer ? that has the contents of the `.hg/dirstate` file. This only applies to the tree-based flavor of `DirstateMap`. For now only the entire `&[u8]` slice is stored, so this is not useful yet. Adding a lifetime parameter to the `DirstateMap` struct (in hg-core) makes Python bindings non-trivial because we keep that struct in a Python object that has a dynamic lifetime tied to Python?s reference-counting and GC. As long as we keep the `PyBytes` that owns the borrowed bytes buffer next to the borrowing struct, the buffer will live long enough for the borrows to stay valid. However this relationship cannot be expressed in safe Rust code in a way that would statisfy they borrow-checker. We use `unsafe` code to erase that lifetime parameter, and encapsulate it in a safe abstraction similar to the owning-ref crate: https://docs.rs/owning_ref/ Differential Revision: https://phab.mercurial-scm.org/D10557
author Simon Sapin <simon.sapin@octobus.net>
date Fri, 30 Apr 2021 18:24:54 +0200
parents e8ae91b1a63d
children 21d25e9ee58e
line wrap: on
line source

//! The revset query language
//!
//! <https://www.mercurial-scm.org/repo/hg/help/revsets>

use crate::errors::HgError;
use crate::repo::Repo;
use crate::revlog::changelog::Changelog;
use crate::revlog::revlog::{Revlog, RevlogError};
use crate::revlog::NodePrefix;
use crate::revlog::{Revision, NULL_REVISION, WORKING_DIRECTORY_HEX};
use crate::Node;

/// Resolve a query string into a single revision.
///
/// Only some of the revset language is implemented yet.
pub fn resolve_single(
    input: &str,
    repo: &Repo,
) -> Result<Revision, RevlogError> {
    let changelog = Changelog::open(repo)?;

    match resolve_rev_number_or_hex_prefix(input, &changelog.revlog) {
        Err(RevlogError::InvalidRevision) => {} // Try other syntax
        result => return result,
    }

    if input == "null" {
        return Ok(NULL_REVISION);
    }

    // TODO: support for the rest of the language here.

    Err(
        HgError::unsupported(format!("cannot parse revset '{}'", input))
            .into(),
    )
}

/// Resolve the small subset of the language suitable for revlogs other than
/// the changelog, such as in `hg debugdata --manifest` CLI argument.
///
/// * A non-negative decimal integer for a revision number, or
/// * An hexadecimal string, for the unique node ID that starts with this
///   prefix
pub fn resolve_rev_number_or_hex_prefix(
    input: &str,
    revlog: &Revlog,
) -> Result<Revision, RevlogError> {
    if let Ok(integer) = input.parse::<i32>() {
        if integer >= 0 && revlog.has_rev(integer) {
            return Ok(integer);
        }
    }
    if let Ok(prefix) = NodePrefix::from_hex(input) {
        if prefix.is_prefix_of(&Node::from_hex(WORKING_DIRECTORY_HEX).unwrap())
        {
            return Err(RevlogError::WDirUnsupported);
        }
        return revlog.get_node_rev(prefix);
    }
    Err(RevlogError::InvalidRevision)
}