#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..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 */