git/diff-provider.h

160 lines
6.5 KiB
C

#ifndef DIFF_PROVIDER_H
#define DIFF_PROVIDER_H
#include "xdiff-interface.h"
/*
* The hunk provider interface sits between naming a pair of file
* versions to diff and computing their changed line ranges.
* Consumers that operate on hunk coordinates route their diff
* through here, so that a provider can answer for the pair before
* its content is loaded.
*
* A hunk provider answers a consumer's request from the pair's
* identity, its blob object ids and the settings that determine the
* diff, before any content is loaded; a request no provider answers
* falls through to the consumer's own computation. Two providers implement this
* interface with different authority. The diff-hunks store
* (diff-hunks.h) is in-process and not authoritative: it may only
* reproduce the builtin result, so it never asserts a pair
* equivalent, and it stands aside wherever a process outranks it. A
* process configured in diff.<driver>.process (diff-process.c) is
* authoritative for its paths: its answer may deliberately differ
* from the builtin diff, including asserting a pair equivalent. The
* interface resolves that authority through a provider chain owned
* by the repository, built on first consultation and released by
* repo_clear(): chain order is the resolution, and the builtin
* computation itself is the chain's terminal provider. A consumer
* never names a provider; it reads the outcome below. Every answer a
* provider serves from identity passes the shared coordinate check
* (diff-provider-internal.h) before any consumer sees it.
*/
struct diff_options;
struct object_id;
struct repository;
/*
* The result of a consultation: two dependent axes flattened into
* their four valid points. The first axis is the state of the
* response: the pair was answered, no provider answered, or (from
* diff_provider_emit_hunks() alone) the attempt failed. The second
* axis exists only in the unanswered state: whether what the caller
* computes for this request may be recorded, the one rule the
* interface imposes on an otherwise free caller. The rule travels
* in the outcome because the knowledge is a provider's while the
* recording is the caller's, and it shares the enum with the state,
* rather than riding a separate flag, so that no meaningless
* combination is representable and -Wswitch forces every consumer
* that switches to place the no-record arm.
*
* These values describe consultations, not providers: the set does
* not grow when a provider is added; a new provider maps onto these
* values inside the interface, so consumer code is written once.
* Each entry point returns a subrange of the set (stated at its
* declaration); a switch over this enum should list every value and
* omit "default:" so -Wswitch keeps it exhaustive, and a caller for
* whom only one value is actionable may compare against that value
* alone.
*/
enum diff_provider_outcome {
/*
* Loading or diffing the pair failed. Returned only by
* diff_provider_emit_hunks(), whose compute leg is the only
* part of a consultation that can fail.
*/
DIFF_PROVIDER_ERROR = -1,
/*
* The request is answered: every hunk of the pair has been
* emitted through the callback. An authoritative provider
* that finds the pair equivalent answers with no hunks at
* all, so a callback that never fired is an answer, not an
* accident.
*/
DIFF_PROVIDER_ANSWERED = 0,
/*
* No provider answered. What happens next is the caller's
* business, typically computing the diff itself; a result it
* computes for this request may be recorded.
*/
DIFF_PROVIDER_UNANSWERED,
/*
* No provider answered, and what the caller computes for
* this request must not be recorded: either an authoritative
* provider owns the pair and declined this request, or the
* request is shaped by parameters outside the recording key,
* the key a recorded result is later served by.
*/
DIFF_PROVIDER_UNANSWERED_NO_RECORD,
};
/*
* A consultation request. The interface consults providers from
* these fields alone; no content is loaded before an answer.
*
* repo owns the provider chain the request walks. old_oid/new_oid
* name the blobs whose bytes are diffed; pass NULL for a side whose
* bytes are not a stored blob (a working-tree file, textconv output,
* a gitlink), so no provider answers from an id it cannot look up.
* path names the file the pair is diffed as; a provider selected by
* path applies only where it is set. diffopt carries the diff
* settings that live outside xpp; xpp carries the parameters the
* diff runs with. Each provider gates itself on the fields that
* concern it.
*/
struct diff_provider_request {
struct repository *repo;
const struct object_id *old_oid;
const struct object_id *new_oid;
const char *path;
struct diff_options *diffopt;
const xpparam_t *xpp;
};
/*
* Consult the providers for the request's pair without computing.
* On DIFF_PROVIDER_ANSWERED the hunks were emitted through hunk_cb
* (0-based emission coordinates, context 0) and were validated
* before the first callback ran, so a consumer may accumulate
* directly into its result. Never returns DIFF_PROVIDER_ERROR.
* The callback's return value is not consulted: emission of a
* validated answer has no error leg, so the callback must return 0.
*/
enum diff_provider_outcome
diff_provider_consult(const struct diff_provider_request *req,
xdl_emit_hunk_consume_func_t hunk_cb, void *cb_data);
/*
* Load the pair's content. Called at most once per request, only
* when the ranges are computed rather than provided. The buffers
* borrow storage owned by the callback's owner.
*/
typedef int (*diff_provider_fill_fn)(void *data, mmfile_t *old_file,
mmfile_t *new_file);
/*
* Consult the providers and, when no identity answer serves the
* request, load the pair's content through fill and compute its
* exact changed ranges (context 0). Emits to hunk_cb either way and
* returns DIFF_PROVIDER_ANSWERED, or DIFF_PROVIDER_ERROR when fill
* or the diff fails. The unanswered outcomes are never returned: a
* pair no provider answers is computed here instead of in the caller.
*/
enum diff_provider_outcome
diff_provider_emit_hunks(const struct diff_provider_request *req,
diff_provider_fill_fn fill, void *fill_data,
xdl_emit_hunk_consume_func_t hunk_cb,
void *cb_data);
/*
* Release the repository's provider chain: stop any provider-owned
* processes and free the providers. Called by repo_clear(); the
* chain builds again on the next consultation.
*/
void diff_providers_clear(struct repository *r);
#endif /* DIFF_PROVIDER_H */