This is preliminary work for the rewriting of native contracts using the new immediate/delayed representation introduced in #1975, although this PR is fairly well-separated (and this is why this is a small separate PR).
In order to efficiently implement the contracts for static record types, which needs to know which fields to lock in the sealed tail, we need a way to split and recombine records which is efficient and preserves field metadata. The current implementation can do without because the immediate part and the delayed part are crammed into one function, and the current implementation is also probably quite inefficient (computing 2 record-as-sets differences in pure Nickel).
This PR adds two primops:
record/split_pair corresponds exactly to what the Rust code eval::merge::split::split is doing: separate a pair of records into 4 parts, the fields that are in one of the operands but not the other, plus the fields that are common (but which is split in two because we have to choose if we take the value and field metadata's from the left operand or from the right operand).
record/disjoint_merge is a fast merge operation when both operands are known to be disjoints. It's closer to a union than a merge, although both coincide on such a special case, in that it doesn't interact with metadata or recursive definitions (although it does preserve metadata). This operation just puts everything in one record.
Those primops might be also useful to efficiently implement other operations (record differences, record projection, etc.) in the stdlibin the future.
This is preliminary work for the rewriting of native contracts using the new immediate/delayed representation introduced in #1975, although this PR is fairly well-separated (and this is why this is a small separate PR).
In order to efficiently implement the contracts for static record types, which needs to know which fields to lock in the sealed tail, we need a way to split and recombine records which is efficient and preserves field metadata. The current implementation can do without because the immediate part and the delayed part are crammed into one function, and the current implementation is also probably quite inefficient (computing 2 record-as-sets differences in pure Nickel).
This PR adds two primops:
record/split_pair
corresponds exactly to what the Rust codeeval::merge::split::split
is doing: separate a pair of records into 4 parts, the fields that are in one of the operands but not the other, plus the fields that are common (but which is split in two because we have to choose if we take the value and field metadata's from the left operand or from the right operand).record/disjoint_merge
is a fast merge operation when both operands are known to be disjoints. It's closer to a union than a merge, although both coincide on such a special case, in that it doesn't interact with metadata or recursive definitions (although it does preserve metadata). This operation just puts everything in one record.Those primops might be also useful to efficiently implement other operations (record differences, record projection, etc.) in the stdlibin the future.