Skip to content

Commit

Permalink
Create Size nodes (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva authored Dec 29, 2023
1 parent 728e68b commit 122bb39
Show file tree
Hide file tree
Showing 30 changed files with 303 additions and 163 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-dodos-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@metaplex-foundation/kinobi': minor
---

Create Size nodes
6 changes: 3 additions & 3 deletions src/nodes/AccountNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
MainCaseString,
PartialExcept,
mainCase,
remainderSize,
} from '../shared';
import { AccountDataNode, accountDataNode } from './AccountDataNode';
import { bytesTypeNode } from './typeNodes/BytesTypeNode';
Expand All @@ -15,6 +14,7 @@ import { stringTypeNode } from './typeNodes/StringTypeNode';
import { assertStructTypeNode } from './typeNodes/StructTypeNode';
import { TypeNode, createTypeNodeFromIdl } from './typeNodes/TypeNode';
import { vScalar } from './ValueNode';
import { remainderSizeNode } from './sizeNodes';

export type AccountNode = {
readonly kind: 'accountNode';
Expand Down Expand Up @@ -63,9 +63,9 @@ export function accountNodeFromIdl(idl: Partial<IdlAccount>): AccountNode {
const value = vScalar(seed.value);
let type: TypeNode;
if (seed.type === 'string') {
type = stringTypeNode({ size: remainderSize() });
type = stringTypeNode({ size: remainderSizeNode() });
} else if (seed.type === 'bytes') {
type = bytesTypeNode(remainderSize());
type = bytesTypeNode(remainderSizeNode());
} else {
type = createTypeNodeFromIdl(seed.type);
}
Expand Down
2 changes: 2 additions & 0 deletions src/nodes/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { InstructionExtraArgsNode } from './InstructionExtraArgsNode';
import type { InstructionNode } from './InstructionNode';
import type { ProgramNode } from './ProgramNode';
import type { RootNode } from './RootNode';
import { REGISTERED_SIZE_NODES } from './sizeNodes';
import { REGISTERED_TYPE_NODES } from './typeNodes';

const REGISTERED_NODES = {
Expand All @@ -24,6 +25,7 @@ const REGISTERED_NODES = {

// Groups.
...REGISTERED_TYPE_NODES,
...REGISTERED_SIZE_NODES,
};

export const REGISTERED_NODES_KEYS = Object.keys(
Expand Down
1 change: 1 addition & 0 deletions src/nodes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export * from './ProgramNode';
export * from './RootNode';
export * from './ValueNode';

export * from './sizeNodes';
export * from './typeNodes';
22 changes: 22 additions & 0 deletions src/nodes/sizeNodes/FixedSizeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Node } from '../Node';

export type FixedSizeNode = {
readonly kind: 'fixedSizeNode';
readonly size: number;
};

export function fixedSizeNode(size: number): FixedSizeNode {
return { kind: 'fixedSizeNode', size };
}

export function isFixedSizeNode(node: Node | null): node is FixedSizeNode {
return !!node && node.kind === 'fixedSizeNode';
}

export function assertFixedSizeNode(
node: Node | null
): asserts node is FixedSizeNode {
if (!isFixedSizeNode(node)) {
throw new Error(`Expected fixedSizeNode, got ${node?.kind ?? 'null'}.`);
}
}
25 changes: 25 additions & 0 deletions src/nodes/sizeNodes/PrefixedSizeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Node } from '../Node';
import { NumberTypeNode } from '../typeNodes';

export type PrefixedSizeNode = {
readonly kind: 'prefixedSizeNode';
readonly prefix: NumberTypeNode;
};

export function prefixedSizeNode(prefix: NumberTypeNode): PrefixedSizeNode {
return { kind: 'prefixedSizeNode', prefix };
}

export function isPrefixedSizeNode(
node: Node | null
): node is PrefixedSizeNode {
return !!node && node.kind === 'prefixedSizeNode';
}

export function assertPrefixedSizeNode(
node: Node | null
): asserts node is PrefixedSizeNode {
if (!isPrefixedSizeNode(node)) {
throw new Error(`Expected prefixedSizeNode, got ${node?.kind ?? 'null'}.`);
}
}
23 changes: 23 additions & 0 deletions src/nodes/sizeNodes/RemainderSizeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Node } from '../Node';

export type RemainderSizeNode = {
readonly kind: 'remainderSizeNode';
};

export function remainderSizeNode(): RemainderSizeNode {
return { kind: 'remainderSizeNode' };
}

export function isRemainderSizeNode(
node: Node | null
): node is RemainderSizeNode {
return !!node && node.kind === 'remainderSizeNode';
}

export function assertRemainderSizeNode(
node: Node | null
): asserts node is RemainderSizeNode {
if (!isRemainderSizeNode(node)) {
throw new Error(`Expected remainderSizeNode, got ${node?.kind ?? 'null'}.`);
}
}
28 changes: 28 additions & 0 deletions src/nodes/sizeNodes/SizeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Node } from '../Node';
import type { FixedSizeNode } from './FixedSizeNode';
import type { PrefixedSizeNode } from './PrefixedSizeNode';
import type { RemainderSizeNode } from './RemainderSizeNode';

export const REGISTERED_SIZE_NODES = {
fixedSizeNode: {} as FixedSizeNode,
remainderSizeNode: {} as RemainderSizeNode,
prefixedSizeNode: {} as PrefixedSizeNode,
};

export const REGISTERED_SIZE_NODE_KEYS = Object.keys(
REGISTERED_SIZE_NODES
) as (keyof typeof REGISTERED_SIZE_NODES)[];

export type RegisteredSizeNodes = typeof REGISTERED_SIZE_NODES;

export type SizeNode = RegisteredSizeNodes[keyof RegisteredSizeNodes];

export function isSizeNode(node: Node | null): node is SizeNode {
return !!node && (REGISTERED_SIZE_NODE_KEYS as string[]).includes(node.kind);
}

export function assertSizeNode(node: Node | null): asserts node is SizeNode {
if (!isSizeNode(node)) {
throw new Error(`Expected typeNode, got ${node?.kind ?? 'null'}.`);
}
}
4 changes: 4 additions & 0 deletions src/nodes/sizeNodes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './FixedSizeNode';
export * from './PrefixedSizeNode';
export * from './RemainderSizeNode';
export * from './SizeNode';
26 changes: 15 additions & 11 deletions src/nodes/typeNodes/ArrayTypeNode.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { IdlTypeArray, IdlTypeVec } from '../../idl';
import {
SizeStrategy,
fixedSize,
prefixedSize,
remainderSize,
} from '../../shared/SizeStrategy';
import type { Node } from '../Node';
import {
SizeNode,
fixedSizeNode,
prefixedSizeNode,
remainderSizeNode,
} from '../sizeNodes';
import { numberTypeNode } from './NumberTypeNode';
import { TypeNode, createTypeNodeFromIdl } from './TypeNode';

export type ArrayTypeNode = {
readonly kind: 'arrayTypeNode';
readonly child: TypeNode;
readonly size: SizeStrategy;
readonly size: SizeNode;
};

export function arrayTypeNode(
Expand All @@ -21,24 +21,28 @@ export function arrayTypeNode(
readonly size?: ArrayTypeNode['size'];
} = {}
): ArrayTypeNode {
return { kind: 'arrayTypeNode', child, size: options.size ?? prefixedSize() };
return {
kind: 'arrayTypeNode',
child,
size: options.size ?? prefixedSizeNode(numberTypeNode('u32')),
};
}

export function arrayTypeNodeFromIdl(
idl: IdlTypeArray | IdlTypeVec
): ArrayTypeNode {
if ('array' in idl) {
const child = createTypeNodeFromIdl(idl.array[0]);
return arrayTypeNode(child, { size: fixedSize(idl.array[1]) });
return arrayTypeNode(child, { size: fixedSizeNode(idl.array[1]) });
}

const child = createTypeNodeFromIdl(idl.vec);
if (!idl.size) return arrayTypeNode(child);
if (idl.size === 'remainder') {
return arrayTypeNode(child, { size: remainderSize() });
return arrayTypeNode(child, { size: remainderSizeNode() });
}
return arrayTypeNode(child, {
size: prefixedSize(numberTypeNode(idl.size)),
size: prefixedSizeNode(numberTypeNode(idl.size)),
});
}

Expand Down
16 changes: 4 additions & 12 deletions src/nodes/typeNodes/BytesTypeNode.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import {
SizeStrategy,
displaySizeStrategy,
remainderSize,
} from '../../shared/SizeStrategy';
import type { Node } from '../Node';
import { SizeNode, remainderSizeNode } from '../sizeNodes';

export type BytesTypeNode = {
readonly kind: 'bytesTypeNode';
readonly size: SizeStrategy;
readonly size: SizeNode;
};

export function bytesTypeNode(size?: SizeStrategy): BytesTypeNode {
return { kind: 'bytesTypeNode', size: size ?? remainderSize() };
}

export function displayBytesTypeNode(node: BytesTypeNode): string {
return `bytes(${displaySizeStrategy(node.size)})`;
export function bytesTypeNode(size?: SizeNode): BytesTypeNode {
return { kind: 'bytesTypeNode', size: size ?? remainderSizeNode() };
}

export function isBytesTypeNode(node: Node | null): node is BytesTypeNode {
Expand Down
26 changes: 13 additions & 13 deletions src/nodes/typeNodes/MapTypeNode.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
import type { IdlTypeMap } from '../../idl';
import {
SizeStrategy,
fixedSize,
prefixedSize,
remainderSize,
} from '../../shared';
import type { Node } from '../Node';
import {
SizeNode,
fixedSizeNode,
prefixedSizeNode,
remainderSizeNode,
} from '../sizeNodes';
import { numberTypeNode } from './NumberTypeNode';
import { TypeNode, createTypeNodeFromIdl } from './TypeNode';

export type MapTypeNode = {
readonly kind: 'mapTypeNode';
readonly key: TypeNode;
readonly value: TypeNode;
readonly size: SizeStrategy;
readonly size: SizeNode;
readonly idlMap: 'hashMap' | 'bTreeMap';
};

export function mapTypeNode(
key: TypeNode,
value: TypeNode,
options: {
readonly size?: SizeStrategy;
readonly size?: MapTypeNode['size'];
readonly idlMap?: MapTypeNode['idlMap'];
} = {}
): MapTypeNode {
return {
kind: 'mapTypeNode',
key,
value,
size: options.size ?? prefixedSize(),
size: options.size ?? prefixedSizeNode(numberTypeNode('u32')),
idlMap: options.idlMap ?? 'hashMap',
};
}

export function mapTypeNodeFromIdl(idl: IdlTypeMap): MapTypeNode {
const [key, value] = 'hashMap' in idl ? idl.hashMap : idl.bTreeMap;
let size: SizeStrategy | undefined;
let size: SizeNode | undefined;
if (idl.size === 'remainder') {
size = remainderSize();
size = remainderSizeNode();
} else if (typeof idl.size === 'number') {
size = fixedSize(idl.size);
size = fixedSizeNode(idl.size);
} else if (idl.size) {
size = prefixedSize(numberTypeNode(idl.size));
size = prefixedSizeNode(numberTypeNode(idl.size));
}
return mapTypeNode(createTypeNodeFromIdl(key), createTypeNodeFromIdl(value), {
size,
Expand Down
24 changes: 12 additions & 12 deletions src/nodes/typeNodes/SetTypeNode.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import type { IdlTypeSet } from '../../idl';
import {
SizeStrategy,
fixedSize,
prefixedSize,
remainderSize,
} from '../../shared';
import type { Node } from '../Node';
import {
SizeNode,
fixedSizeNode,
prefixedSizeNode,
remainderSizeNode,
} from '../sizeNodes';
import { numberTypeNode } from './NumberTypeNode';
import { TypeNode, createTypeNodeFromIdl } from './TypeNode';

export type SetTypeNode = {
readonly kind: 'setTypeNode';
readonly child: TypeNode;
readonly size: SizeStrategy;
readonly size: SizeNode;
readonly idlSet: 'hashSet' | 'bTreeSet';
};

export function setTypeNode(
child: TypeNode,
options: {
readonly size?: SizeStrategy;
readonly size?: SetTypeNode['size'];
readonly idlSet?: SetTypeNode['idlSet'];
} = {}
): SetTypeNode {
return {
kind: 'setTypeNode',
child,
size: options.size ?? prefixedSize(),
size: options.size ?? prefixedSizeNode(numberTypeNode('u32')),
idlSet: options.idlSet ?? 'hashSet',
};
}
Expand All @@ -35,11 +35,11 @@ export function setTypeNodeFromIdl(idl: IdlTypeSet): SetTypeNode {
const child = 'hashSet' in idl ? idl.hashSet : idl.bTreeSet;
let size: SetTypeNode['size'] | undefined;
if (idl.size === 'remainder') {
size = remainderSize();
size = remainderSizeNode();
} else if (typeof idl.size === 'number') {
size = fixedSize(idl.size);
size = fixedSizeNode(idl.size);
} else if (idl.size) {
size = prefixedSize(numberTypeNode(idl.size));
size = prefixedSizeNode(numberTypeNode(idl.size));
}
return setTypeNode(createTypeNodeFromIdl(child), {
size,
Expand Down
Loading

0 comments on commit 122bb39

Please sign in to comment.