from rust
This commit is contained in:
parent
32203fadc0
commit
1f00cff032
8 changed files with 598 additions and 323 deletions
166
source/xdiff_mmfile.d
Normal file
166
source/xdiff_mmfile.d
Normal file
|
@ -0,0 +1,166 @@
|
|||
module xdiff_mmfile;
|
||||
|
||||
import std.exception : enforce;
|
||||
import xdiff_init : ensureInit, initMmfile;
|
||||
import xdiff_mmblocks : MMBlocks;
|
||||
import xdiff;
|
||||
|
||||
final class MMFile
|
||||
{
|
||||
private:
|
||||
mmfile_t _inner;
|
||||
bool _owned = true;
|
||||
|
||||
public:
|
||||
this()
|
||||
{
|
||||
_inner = initMmfile(0);
|
||||
}
|
||||
|
||||
static MMFile fromBytes(const(ubyte)[] data)
|
||||
{
|
||||
auto f = new MMFile;
|
||||
if (data.length > 0)
|
||||
{
|
||||
auto wrote = xdl_write_mmfile(&f._inner, data.ptr, cast(long)data.length);
|
||||
enforce(wrote == cast(long)data.length, "xdl_write_mmfile wrote less than requested");
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
if (_owned && _inner.head !is null)
|
||||
xdl_free_mmfile(&_inner);
|
||||
|
||||
_inner.head = null; _inner.tail = null;
|
||||
_inner.rcur = null; _inner.wcur = null;
|
||||
_inner.fsize = 0; _inner.bsize = 0;
|
||||
}
|
||||
|
||||
size_t size() { return cast(size_t)xdl_mmfile_size(&_inner); }
|
||||
bool isCompact() const { return xdl_mmfile_iscompact(cast(mmfile_t*)&_inner) != 0; }
|
||||
|
||||
const(ubyte)[] asSlice() const
|
||||
{
|
||||
enforce(isCompact(), "MMFile must be compact for asSlice");
|
||||
auto h = _inner.head;
|
||||
if (h is null || h.size <= 0) return (cast(ubyte*)null)[0 .. 0];
|
||||
return (cast(const(ubyte)*)h.ptr)[0 .. cast(size_t)h.size];
|
||||
}
|
||||
|
||||
ubyte[] asSliceMut()
|
||||
{
|
||||
enforce(isCompact(), "MMFile must be compact for asSliceMut");
|
||||
auto h = _inner.head;
|
||||
if (h is null || h.size <= 0) return (cast(ubyte*)null)[0 .. 0];
|
||||
return (cast(ubyte*)h.ptr)[0 .. cast(size_t)h.size];
|
||||
}
|
||||
|
||||
alias MMPatch = MMBlocks;
|
||||
|
||||
/// Сформировать patch (diff self → other)
|
||||
MMPatch computePatch(ref MMFile other)
|
||||
{
|
||||
auto patch = new MMBlocks();
|
||||
|
||||
static extern(C) int emitToPatch(void* priv, mmbuffer_t* bufs, int num)
|
||||
{
|
||||
auto target = cast(MMBlocks)priv; // класс
|
||||
foreach (i; 0 .. num)
|
||||
{
|
||||
auto b = bufs + i;
|
||||
auto wrote = xdl_writem_mmfile(target.mmfilePtr(), b, 1);
|
||||
if (wrote != (*b).size) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
xpparam_t xpp; xpp.flags = 0;
|
||||
xdemitconf_t xec; xec.ctxlen = 3;
|
||||
xdemitcb_t ecb; ecb.priv = cast(void*)patch; ecb.outf = &emitToPatch;
|
||||
|
||||
auto rc = xdl_diff(&_inner, &other._inner, &xpp, &xec, &ecb);
|
||||
enforce(rc == 0, "xdl_diff failed");
|
||||
return patch;
|
||||
}
|
||||
|
||||
struct PatchResult { bool success; MMFile patched; MMFile rejected; }
|
||||
|
||||
/// Применить patch к self
|
||||
PatchResult applyPatch(ref MMPatch patch)
|
||||
{
|
||||
patch.toCompact();
|
||||
|
||||
auto acc = new MMBlocks();
|
||||
auto rej = new MMBlocks();
|
||||
|
||||
static extern(C) int emitTo(void* priv, mmbuffer_t* bufs, int num)
|
||||
{
|
||||
auto target = cast(MMBlocks)priv; // класс
|
||||
long expect = 0; foreach (i; 0 .. num) expect += (bufs + i).size;
|
||||
auto wrote = xdl_writem_mmfile(target.mmfilePtr(), bufs, num);
|
||||
return (wrote == expect) ? 0 : -1;
|
||||
}
|
||||
|
||||
xdemitcb_t accCb; accCb.priv = cast(void*)acc; accCb.outf = &emitTo;
|
||||
xdemitcb_t rejCb; rejCb.priv = cast(void*)rej; rejCb.outf = &emitTo;
|
||||
|
||||
auto rc = xdl_patch(&_inner, patch.mmfilePtr(), XDL_PATCH_NORMAL, &accCb, &rejCb);
|
||||
enforce(rc == 0 || rc == 1, "xdl_patch failed");
|
||||
|
||||
auto accFile = MMFile.fromBlocksMoved(acc);
|
||||
auto rejFile = MMFile.fromBlocksMoved(rej);
|
||||
|
||||
bool ok = (rejFile.size() == 0);
|
||||
return PatchResult(ok, accFile, rejFile);
|
||||
}
|
||||
|
||||
/// 3-way merge: коллбэки nothrow, чтобы не бросать через C
|
||||
void merge3Raw(
|
||||
ref MMFile f1,
|
||||
ref MMFile f2,
|
||||
scope int delegate(const(ubyte)[]) nothrow acceptCb,
|
||||
scope int delegate(const(ubyte)[]) nothrow rejectCb)
|
||||
{
|
||||
static extern(C) int emitAccept(void* priv, mmbuffer_t* bufs, int num)
|
||||
{
|
||||
auto d = cast(int delegate(const(ubyte)[]) nothrow*)priv;
|
||||
foreach (i; 0 .. num)
|
||||
{
|
||||
auto b = bufs + i;
|
||||
auto slice = (cast(const(ubyte)*)((*b).ptr))[0 .. cast(size_t)((*b).size)];
|
||||
auto r = (*d)(slice); if (r != 0) return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static extern(C) int emitReject(void* priv, mmbuffer_t* bufs, int num)
|
||||
{
|
||||
auto d = cast(int delegate(const(ubyte)[]) nothrow*)priv;
|
||||
foreach (i; 0 .. num)
|
||||
{
|
||||
auto b = bufs + i;
|
||||
auto slice = (cast(const(ubyte)*)((*b).ptr))[0 .. cast(size_t)((*b).size)];
|
||||
auto r = (*d)(slice); if (r != 0) return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto a = acceptCb, r = rejectCb;
|
||||
xdemitcb_t accCb; accCb.priv = cast(void*)&a; accCb.outf = &emitAccept;
|
||||
xdemitcb_t rejCb; rejCb.priv = cast(void*)&r; rejCb.outf = &emitReject;
|
||||
|
||||
auto rc = xdl_merge3(&_inner, &f1._inner, &f2._inner, &accCb, &rejCb);
|
||||
enforce(rc == 0, "xdl_merge3 failed");
|
||||
}
|
||||
|
||||
/// «Move» из MMBlocks: забрать владение внутренними блоками
|
||||
static MMFile fromBlocksMoved(MMBlocks b)
|
||||
{
|
||||
b.toCompact();
|
||||
auto f = new MMFile;
|
||||
f._inner = *b.mmfilePtr(); // копируем заголовок (указатели на блоки)
|
||||
b.disarm(); // источник больше не владеет
|
||||
return f;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue