<commit_before>import { MuSchema } from './schema';
import { MuWriteStream, MuReadStream } from 'mustreams';

// tslint:disable-next-line:class-name
export interface _TypeDataPair<SubTypes extends { [type:string]:MuSchema<any> }> {
    type:keyof SubTypes;
    data:SubTypes[keyof SubTypes]['identity'];
}

export class MuUnion<SubTypes extends { [type:string]:MuSchema<any> }>
        implements MuSchema<_TypeDataPair<SubTypes>> {
    private _types:string[];

    public readonly identity:_TypeDataPair<SubTypes>;

    public readonly muType = 'union';
    public readonly muData:SubTypes;
    public readonly json:object;

    constructor (
        schemaSpec:SubTypes,
        identityType?:keyof SubTypes,
    ) {
        this._types = Object.keys(schemaSpec);
        this.muData = schemaSpec;

        if (identityType) {
            this.identity = {
                type: identityType,
                data: schemaSpec[identityType].identity,
            };
        } else {
            this.identity = {
                type: '',
                data: void 0,
            };
        }

        const result = {};
        Object.keys(schemaSpec).forEach((subtype) => {
            result[subtype] = this.muData[subtype].json;
        });
        this.json = {
            type: 'union',
            identity: this.identity.type,
            data: result,
        };
    }

    public alloc () : _TypeDataPair<SubTypes> {
        return {
            type: '',
            data: void 0,
        };
    }

    public free (data:_TypeDataPair<SubTypes>) {
        this.muData[data.type].free(data.data);
    }

    public clone (data:_TypeDataPair<SubTypes>) : _TypeDataPair<SubTypes> {
        const schema = this.muData[data.type];
        return {
            type: data.type,
            data: schema.clone(data.data),
        };
    }

    public diff (
        base:_TypeDataPair<SubTypes>,
        target:_TypeDataPair<SubTypes>,
        stream:MuWriteStream,
    ) : boolean {
        stream.grow(8);

        const trackerOffset = stream.offset;
        ++stream.offset;

        let tracker = 0;

        const dataSchema = this.muData[target.type];
        if (base.type === target.type) {
            if (dataSchema.diff(base.data, target.data, stream)) {
                tracker = 1;
            }
        } else {
            stream.writeUint8(this._types.indexOf(target.type));
            if (dataSchema.diff(dataSchema.identity, target.data, stream)) {
                tracker = 2;
            } else {
                tracker = 4;
            }
        }

        if (tracker) {
            stream.writeUint8At(trackerOffset, tracker);
            return true;
        }
        stream.offset = trackerOffset;<commit_msg>schema: assert target.type as string<commit_after>import { MuSchema } from './schema';
import { MuWriteStream, MuReadStream } from 'mustreams';

// tslint:disable-next-line:class-name
export interface _TypeDataPair<SubTypes extends { [type:string]:MuSchema<any> }> {
    type:keyof SubTypes;
    data:SubTypes[keyof SubTypes]['identity'];
}

export class MuUnion<SubTypes extends { [type:string]:MuSchema<any> }>
        implements MuSchema<_TypeDataPair<SubTypes>> {
    private _types:string[];

    public readonly identity:_TypeDataPair<SubTypes>;

    public readonly muType = 'union';
    public readonly muData:SubTypes;
    public readonly json:object;

    constructor (
        schemaSpec:SubTypes,
        identityType?:keyof SubTypes,
    ) {
        this._types = Object.keys(schemaSpec);
        this.muData = schemaSpec;

        if (identityType) {
            this.identity = {
                type: identityType,
                data: schemaSpec[identityType].identity,
            };
        } else {
            this.identity = {
                type: '',
                data: void 0,
            };
        }

        const result = {};
        Object.keys(schemaSpec).forEach((subtype) => {
            result[subtype] = this.muData[subtype].json;
        });
        this.json = {
            type: 'union',
            identity: this.identity.type,
            data: result,
        };
    }

    public alloc () : _TypeDataPair<SubTypes> {
        return {
            type: '',
            data: void 0,
        };
    }

    public free (data:_TypeDataPair<SubTypes>) {
        this.muData[data.type].free(data.data);
    }

    public clone (data:_TypeDataPair<SubTypes>) : _TypeDataPair<SubTypes> {
        const schema = this.muData[data.type];
        return {
            type: data.type,
            data: schema.clone(data.data),
        };
    }

    public diff (
        base:_TypeDataPair<SubTypes>,
        target:_TypeDataPair<SubTypes>,
        stream:MuWriteStream,
    ) : boolean {
        stream.grow(8);

        const trackerOffset = stream.offset;
        ++stream.offset;

        let tracker = 0;

        const dataSchema = this.muData[target.type];
        if (base.type === target.type) {
            if (dataSchema.diff(base.data, target.data, stream)) {
                tracker = 1;
            }
        } else {
            stream.writeUint8(this._types.indexOf(target.type as string));
            if (dataSchema.diff(dataSchema.identity, target.data, stream)) {
                tracker = 2;
            } else {
                tracker = 4;
            }
        }

        if (tracker) {
            stream.writeUint8At(trackerOffset, tracker);
            return true;
        }
        stream.offset = trackerOffset;
{'fraction_non_alphanumeric': 0.1158371040723982, 'fraction_numerical': 0.003257918552036199, 'mean_word_length': 1.833846153846154, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5190702', 'n_tokens_mistral': 1594, 'n_tokens_neox': 1532, 'n_words': 291}