| 1 | #ifndef DIFF_PROVIDER_H |
| 2 | #define DIFF_PROVIDER_H |
| 3 | |
| 4 | #include "xdiff-interface.h" |
| 5 | |
| 6 | /* |
| 7 | * The hunk provider interface sits between naming a pair of file |
| 8 | * versions to diff and computing their changed line ranges. |
| 9 | * Consumers that operate on hunk coordinates route their diff |
| 10 | * through here, so that a provider can answer for the pair before |
| 11 | * its content is loaded. |
| 12 | * |
| 13 | * A hunk provider answers a consumer's request from the pair's |
| 14 | * identity, its blob object ids and the settings that determine the |
| 15 | * diff, before any content is loaded; a request no provider answers |
| 16 | * falls through to the consumer's own computation. Two providers implement this |
| 17 | * interface with different authority. The diff-hunks store |
| 18 | * (diff-hunks.h) is in-process and not authoritative: it may only |
| 19 | * reproduce the builtin result, so it never asserts a pair |
| 20 | * equivalent, and it stands aside wherever a process outranks it. A |
| 21 | * process configured in diff.<driver>.process (diff-process.c) is |
| 22 | * authoritative for its paths: its answer may deliberately differ |
| 23 | * from the builtin diff, including asserting a pair equivalent. The |
| 24 | * interface resolves that authority through a provider chain owned |
| 25 | * by the repository, built on first consultation and released by |
| 26 | * repo_clear(): chain order is the resolution, and the builtin |
| 27 | * computation itself is the chain's terminal provider. A consumer |
| 28 | * never names a provider; it reads the outcome below. Every answer a |
| 29 | * provider serves from identity passes the shared coordinate check |
| 30 | * (diff-provider-internal.h) before any consumer sees it. |
| 31 | */ |
| 32 | |
| 33 | struct diff_options; |
| 34 | struct object_id; |
| 35 | struct repository; |
| 36 | |
| 37 | /* |
| 38 | * The result of a consultation: two dependent axes flattened into |
| 39 | * their four valid points. The first axis is the state of the |
| 40 | * response: the pair was answered, no provider answered, or (from |
| 41 | * diff_provider_emit_hunks() alone) the attempt failed. The second |
| 42 | * axis exists only in the unanswered state: whether what the caller |
| 43 | * computes for this request may be recorded, the one rule the |
| 44 | * interface imposes on an otherwise free caller. The rule travels |
| 45 | * in the outcome because the knowledge is a provider's while the |
| 46 | * recording is the caller's, and it shares the enum with the state, |
| 47 | * rather than riding a separate flag, so that no meaningless |
| 48 | * combination is representable and -Wswitch forces every consumer |
| 49 | * that switches to place the no-record arm. |
| 50 | * |
| 51 | * These values describe consultations, not providers: the set does |
| 52 | * not grow when a provider is added; a new provider maps onto these |
| 53 | * values inside the interface, so consumer code is written once. |
| 54 | * Each entry point returns a subrange of the set (stated at its |
| 55 | * declaration); a switch over this enum should list every value and |
| 56 | * omit "default:" so -Wswitch keeps it exhaustive, and a caller for |
| 57 | * whom only one value is actionable may compare against that value |
| 58 | * alone. |
| 59 | */ |
| 60 | enum diff_provider_outcome { |
| 61 | /* |
| 62 | * Loading or diffing the pair failed. Returned only by |
| 63 | * diff_provider_emit_hunks(), whose compute leg is the only |
| 64 | * part of a consultation that can fail. |
| 65 | */ |
| 66 | DIFF_PROVIDER_ERROR = -1, |
| 67 | |
| 68 | /* |
| 69 | * The request is answered: every hunk of the pair has been |
| 70 | * emitted through the callback. An authoritative provider |
| 71 | * that finds the pair equivalent answers with no hunks at |
| 72 | * all, so a callback that never fired is an answer, not an |
| 73 | * accident. |
| 74 | */ |
| 75 | DIFF_PROVIDER_ANSWERED = 0, |
| 76 | |
| 77 | /* |
| 78 | * No provider answered. What happens next is the caller's |
| 79 | * business, typically computing the diff itself; a result it |
| 80 | * computes for this request may be recorded. |
| 81 | */ |
| 82 | DIFF_PROVIDER_UNANSWERED, |
| 83 | |
| 84 | /* |
| 85 | * No provider answered, and what the caller computes for |
| 86 | * this request must not be recorded: either an authoritative |
| 87 | * provider owns the pair and declined this request, or the |
| 88 | * request is shaped by parameters outside the recording key, |
| 89 | * the key a recorded result is later served by. |
| 90 | */ |
| 91 | DIFF_PROVIDER_UNANSWERED_NO_RECORD, |
| 92 | }; |
| 93 | |
| 94 | /* |
| 95 | * A consultation request. The interface consults providers from |
| 96 | * these fields alone; no content is loaded before an answer. |
| 97 | * |
| 98 | * repo owns the provider chain the request walks. old_oid/new_oid |
| 99 | * name the blobs whose bytes are diffed; pass NULL for a side whose |
| 100 | * bytes are not a stored blob (a working-tree file, textconv output, |
| 101 | * a gitlink), so no provider answers from an id it cannot look up. |
| 102 | * path names the file the pair is diffed as; a provider selected by |
| 103 | * path applies only where it is set. diffopt carries the diff |
| 104 | * settings that live outside xpp; xpp carries the parameters the |
| 105 | * diff runs with. Each provider gates itself on the fields that |
| 106 | * concern it. |
| 107 | */ |
| 108 | struct diff_provider_request { |
| 109 | struct repository *repo; |
| 110 | const struct object_id *old_oid; |
| 111 | const struct object_id *new_oid; |
| 112 | const char *path; |
| 113 | struct diff_options *diffopt; |
| 114 | const xpparam_t *xpp; |
| 115 | }; |
| 116 | |
| 117 | /* |
| 118 | * Consult the providers for the request's pair without computing. |
| 119 | * On DIFF_PROVIDER_ANSWERED the hunks were emitted through hunk_cb |
| 120 | * (0-based emission coordinates, context 0) and were validated |
| 121 | * before the first callback ran, so a consumer may accumulate |
| 122 | * directly into its result. Never returns DIFF_PROVIDER_ERROR. |
| 123 | * The callback's return value is not consulted: emission of a |
| 124 | * validated answer has no error leg, so the callback must return 0. |
| 125 | */ |
| 126 | enum diff_provider_outcome |
| 127 | diff_provider_consult(const struct diff_provider_request *req, |
| 128 | xdl_emit_hunk_consume_func_t hunk_cb, void *cb_data); |
| 129 | |
| 130 | /* |
| 131 | * Load the pair's content. Called at most once per request, only |
| 132 | * when the ranges are computed rather than provided. The buffers |
| 133 | * borrow storage owned by the callback's owner. |
| 134 | */ |
| 135 | typedef int (*diff_provider_fill_fn)(void *data, mmfile_t *old_file, |
| 136 | mmfile_t *new_file); |
| 137 | |
| 138 | /* |
| 139 | * Consult the providers and, when no identity answer serves the |
| 140 | * request, load the pair's content through fill and compute its |
| 141 | * exact changed ranges (context 0). Emits to hunk_cb either way and |
| 142 | * returns DIFF_PROVIDER_ANSWERED, or DIFF_PROVIDER_ERROR when fill |
| 143 | * or the diff fails. The unanswered outcomes are never returned: a |
| 144 | * pair no provider answers is computed here instead of in the caller. |
| 145 | */ |
| 146 | enum diff_provider_outcome |
| 147 | diff_provider_emit_hunks(const struct diff_provider_request *req, |
| 148 | diff_provider_fill_fn fill, void *fill_data, |
| 149 | xdl_emit_hunk_consume_func_t hunk_cb, |
| 150 | void *cb_data); |
| 151 | |
| 152 | /* |
| 153 | * Release the repository's provider chain: stop any provider-owned |
| 154 | * processes and free the providers. Called by repo_clear(); the |
| 155 | * chain builds again on the next consultation. |
| 156 | */ |
| 157 | void diff_providers_clear(struct repository *r); |
| 158 | |
| 159 | #endif /* DIFF_PROVIDER_H */ |