diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c --- a/mercurial/cext/parsers.c +++ b/mercurial/cext/parsers.c @@ -155,6 +155,48 @@ static PyObject *dirstate_item_need_dela } }; +/* This will never change since it's bound to V1, unlike `make_dirstate_item` + */ +static inline dirstateItemObject * +dirstate_item_from_v1_data(char state, int mode, int size, int mtime) +{ + dirstateItemObject *t = + PyObject_New(dirstateItemObject, &dirstateItemType); + if (!t) { + return NULL; + } + t->state = state; + t->mode = mode; + t->size = size; + t->mtime = mtime; + return t; +} + +/* This will never change since it's bound to V1, unlike `dirstate_item_new` */ +static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype, + PyObject *args) +{ + /* We do all the initialization here and not a tp_init function because + * dirstate_item is immutable. */ + dirstateItemObject *t; + char state; + int size, mode, mtime; + if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) { + return NULL; + } + + t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1); + if (!t) { + return NULL; + } + t->state = state; + t->mode = mode; + t->size = size; + t->mtime = mtime; + + return (PyObject *)t; +}; + static PyMethodDef dirstate_item_methods[] = { {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS, "return a \"state\" suitable for v1 serialization"}, @@ -166,6 +208,8 @@ static PyMethodDef dirstate_item_methods "return a \"mtime\" suitable for v1 serialization"}, {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O, "True if the stored mtime would be ambiguous with the current time"}, + {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth, METH_O, + "build a new DirstateItem object from V1 data"}, {NULL} /* Sentinel */ }; @@ -363,8 +407,8 @@ static PyObject *parse_dirstate(PyObject goto quit; } - entry = - (PyObject *)make_dirstate_item(state, mode, size, mtime); + entry = (PyObject *)dirstate_item_from_v1_data(state, mode, + size, mtime); cpos = memchr(cur, 0, flen); if (cpos) { fname = PyBytes_FromStringAndSize(cur, cpos - cur); diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py --- a/mercurial/pure/parsers.py +++ b/mercurial/pure/parsers.py @@ -67,6 +67,20 @@ class DirstateItem(object): self._size = size self._mtime = mtime + @classmethod + def from_v1_data(cls, state, mode, size, mtime): + """Build a new DirstateItem object from V1 data + + Since the dirstate-v1 format is frozen, the signature of this function + is not expected to change, unlike the __init__ one. + """ + return cls( + state=state, + mode=mode, + size=size, + mtime=mtime, + ) + def __getitem__(self, idx): if idx == 0 or idx == -4: msg = b"do not use item[x], use item.state" @@ -546,7 +560,7 @@ def parse_dirstate(dmap, copymap, st): if b'\0' in f: f, c = f.split(b'\0') copymap[f] = c - dmap[f] = DirstateItem(*e[:4]) + dmap[f] = DirstateItem.from_v1_data(*e[:4]) return parents