Raw
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 */