export const noop = <T extends unknown>(arg?: T) => { };
export const identity = <T extends unknown>(args: T) => args;

export function invert(invertable: boolean): boolean;
export function invert(invertable: (toggle: boolean) => void): (toggle: boolean) => void;
export function invert(invertable: boolean | ((toggle: boolean) => void)) {
  return (typeof invertable === 'function')
    ? (toggle: boolean) => invertable(!toggle)
    : !invertable;
}

export const compose = <T>(...functions: ((val: T) => T)[]): (val: T) => T => (
  (input: T): T => functions.reduceRight((value, func) => func(value), input)
);
export const series = async <T>(functions: ((val: T) => Promise<T>)[], input: T): Promise<T> => {
  let result = input;

  for (const func of functions) {
    result = await func(result);
  }

  return result;
};
export const sequence = async <T>(...functions: ((val: T) => void)[]): Promise<(val: T) => void> => {
  return (input: T): void => {
    for (const func of functions) {
      func(input);
    }
  };
}
