#ifndef MIDLTESTS_C_CODE

[
  uuid("225b9fcb-eb3d-497b-8b0b-591f049a2507"),
  pointer_default(unique)
]
interface midltests
{
	typedef pipe char pipe_char;
	typedef pipe hyper pipe_hyper;

	struct msg {
		long l;
		[size_is(l)] char *m;
	};

	long midltests_fn(
		[out,ref] struct msg *out1,
		[out] pipe_hyper outp,
		[in] pipe_hyper inp,
		[in] struct msg in1
	);
}

#elif MIDLTESTS_C_CODE

struct pipe_char_state {
	const char *name;
	unsigned long count;
	unsigned long sleep;
};

void pipe_char_pull(
            char * _state,
            unsigned char * buf,
            unsigned long esize,
            unsigned long * ecount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("pull1:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
	*ecount = state->count--;
	if (*ecount > esize) {
		*ecount = esize;
	}
	memset(buf, 0xDD, *ecount * sizeof(*buf));
	printf("pull2:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
}

void pipe_char_push(
            char * _state,
            unsigned char * buf,
            unsigned long ecount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("push:%s: ecount[%u]\n",
		state->name, ecount);
}

void pipe_char_alloc(
            char * _state,
            unsigned long bsize,
            unsigned char * * buf,
            unsigned long * bcount)
{
	struct pipe_char_state *state = (struct pipe_char_state *)_state;

	printf("alloc1:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
	*bcount = bsize / sizeof(**buf);
	*buf = malloc(*bcount * sizeof(**buf));
	printf("alloc2:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
}

struct pipe_hyper_state {
	const char *name;
	unsigned long count;
	unsigned long sleep;
};

void pipe_hyper_pull(
            char * _state,
            hyper * buf,
            unsigned long esize,
            unsigned long * ecount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("pull1:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
	*ecount = state->count--;
	if (*ecount > esize) {
		*ecount = esize;
	}
	memset(buf, 0xDD, *ecount * sizeof(*buf));
	printf("pull2:%s: esize[%u] ecount[%u]\n",
		state->name, esize, *ecount);
}

void pipe_hyper_push(
            char * _state,
            hyper * buf,
            unsigned long ecount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("push:%s: ecount[%u]\n",
		state->name, ecount);
}

void pipe_hyper_alloc(
            char * _state,
            unsigned long bsize,
            hyper * * buf,
            unsigned long * bcount)
{
	struct pipe_hyper_state *state = (struct pipe_hyper_state *)_state;

	printf("alloc1:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
	*bcount = bsize / sizeof(**buf);
	*buf = malloc(*bcount * sizeof(**buf));
	printf("alloc2:%s: bsize[%u], bcount[%u]\n",
		state->name, bsize, *bcount);
}
static void midltests(void)
{
	struct msg out1;
	unsigned char out1b[3];
	struct pipe_hyper_state outs;
	pipe_hyper outp;
	struct pipe_hyper_state ins;
	pipe_hyper inp;
	struct msg in1;
	unsigned char in1b[3];

	in1.l = sizeof(in1b);
	memset(&in1b, 0xAA, sizeof(in1b));
	in1.m = in1b;

	memset(&outs, 0, sizeof(outs));
	outs.name = "outp";
	memset(&outp, 0, sizeof(outp));
	outp.pull = pipe_hyper_pull;
	outp.push = pipe_hyper_push;
	outp.alloc = pipe_hyper_alloc;
	outp.state = (char *)&outs;

	memset(&ins, 0, sizeof(ins));
	ins.name = "inp";
	ins.count = 1;
	memset(&inp, 0, sizeof(inp));
	inp.pull = pipe_hyper_pull;
	inp.push = pipe_hyper_push;
	inp.alloc = pipe_hyper_alloc;
	inp.state = (char *)&ins;

	out1.l = sizeof(out1b);
	memset(&out1b, 0xFF, sizeof(out1b));
	out1.m = out1b;

	cli_midltests_fn(&out1, outp, inp, in1);
}

long srv_midltests_fn(
	    /* [ref][out] */ struct msg *out1,
    /* [out] */ pipe_hyper outp,
    /* [in] */ pipe_hyper inp,
    /* [in] */ struct msg in1)
{
	hyper inb[500];
	unsigned long inb_len = 0;
	hyper *outb = NULL;
	unsigned long outb_size = 0;
	unsigned long outb_len = 0; 

	printf("srv_midltests_fn: Start\n");

	do {
		inp.pull(inp.state, inb, sizeof(inb), &inb_len);
		printf("pull inp_len[%u]\n", inb_len);
	} while (inb_len > 0);

	outb_size = 5;
	do {
		outp.alloc(outp.state, outb_size, &outb, &outb_len);
		memset(outb, 0xCC, outb_len * sizeof(*outb));
		outp.push(outp.state, outb, outb_len);
		printf("push outb_len[%u]\n", outb_len);
		//Sleep(1000);
		outb_size--;
	} while (outb_len > 0);

	out1->l = 3;
	out1->m = (unsigned char *)malloc(out1->l);
	memset(out1->m, 0xBB, out1->l);
	printf("srv_midltests_fn: End\n");
	return 0x65757254;
}

#endif