const CANCEL = Symbol();

export interface CancellationToken {
	readonly IsCancellationRequested: boolean;

	ThrowIfCancellationRequested(): void;
}

export class CancellationTokenSource {
	readonly Token: CancellationToken;

	constructor() {
		this.Token = new CancellationTokenImpl();
	}

	Cancel() {
		this.Token[CANCEL]();
	}
}

export class TaskCancelledException extends Error {
	constructor() {
		super("Task Cancelled");
		Reflect.setPrototypeOf(this, TaskCancelledException.prototype);
	}
}

class CancellationTokenImpl implements CancellationToken {
	IsCancellationRequested: boolean;

	constructor() {
		this.IsCancellationRequested = false;
	}

	ThrowIfCancellationRequested() {
		if (this.IsCancellationRequested) {
			throw new TaskCancelledException();
		}
	}

	[CANCEL]() {
		this.IsCancellationRequested = true;
	}
}
