Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when trying to use deep nested types #121

Open
SeanTasker opened this issue Apr 11, 2019 · 0 comments
Open

Error when trying to use deep nested types #121

SeanTasker opened this issue Apr 11, 2019 · 0 comments

Comments

@SeanTasker
Copy link

SeanTasker commented Apr 11, 2019

Hello,

Thanks for this implementation, it has really saved me a ton of time and avoided adding another serialisation layer to interface with our JavaScript code.

My project is designed to run in a browser, I can confirm that capnp-ts work in browsers. This is the first problem I've run into while using the library.

Given the following structures:

struct ANumber
{
	value @0: Int32;
}

struct AString
{
	value @0: Text;
}

struct StructContainer
{
	name @0: Text;
	number @1: Float64;
	value @2 :AnyPointer;
}

struct StructListContainer
{
	values @0 :List(StructContainer);
}

struct GenericValue
{
	isString @0: Bool;
	isRange @1: Bool;
	value @2: AnyPointer;
}

struct Setting
{
	name @0: Text;
	category @1: Text;
	readOnly @2: Bool;
	value @3: GenericValue;
	validValues @4 :List(GenericValue);
}

I am attempting to create the following hierarchy of objects:

StructContainer
	StructListContainer
		0 - StructContainer
			Setting
				GenericValue
					AString
		.
		.
		N - StructContainer
			Setting
				GenericValue
					AString

However I get the following error when a call StructContainer.setValue() where the value is an initialised StructListContainer.

Uncaught Error: CAPNP-TS019 Pointer offset 0x00000140 is out of bounds for underlying buffer

Except if the inner StructContainer (in the list) are pointing to AString instead of Setting I do not get the error. i.e. the following works fine:

StructContainer
	StructListContainer
		0 StructContainer
			AString
		.
		.
		N - StructContainer
			AString

I use the same code to build the list container and inner structs, with the StructContainer being passed in as an array of any (which will be a Struct of sorts):

function SerialiseStructContainer(builder: Structures.StructContainer, value: any): void
{
	builder.setName("SomeStruct");
	builder.setNumber(987.654);
	builder.setValue(value);
}
 
function SerialiseStructListContainer(builder: Structures.StructContainer, values: any[]): void
{
	builder.setNumber(123.456);
	builder.setName("Test");
	
	// To set the value in StructContainer so that it points to a StructListContainer I initialise
	// a message then call setValue()
	
	var message = new capnp.Message();
	let container = message.initRoot(Structures.StructListContainer);
	if(values.length>0)
	{
		let valuesBuilders = container.initValues(values.length);

		let i=0;
		for (let it of values)
		{
			SerialiseStructContainer(valuesBuilders.get(i),it);
			i++;
		}
	}
	
	// This is where the exception is thrown in the BuildDeep() example
	builder.setValue(container);
}

And finally the code to attempt to build each of the structures is as follows.

The shallow hierarchy:

function BuildShallow(): void
{
	let messages: capnp.Message[] = [];
	let objects: Structures.AString[] = [];

	let count = 10;
	console.log("Creating",count,"objects");
	for(let i=0;i<count;i++)
	{
		var message = new capnp.Message();
		let someStructObject = message.initRoot(Structures.AString);
		let someTestValue = "TestValue" + i.toString();
		someStructObject.setValue(someTestValue);
		messages.push(message);
		objects.push(someStructObject);
	}

	var message = new capnp.Message();
	let mainContainer = message.initRoot(Structures.StructContainer);

	console.log("Calling SerialiseStructListContainer()");
	SerialiseStructListContainer(mainContainer, objects);
	console.log("Done");
}

And the deep hierarchy:

function SetSettingValue(setting: Structures.Setting, value: string): void
{
	// Initialise a GenericValue
	let settingValue = setting.initValue();
	settingValue.setIsString(true);
	settingValue.setIsRange(false);

	//settingValue.setValue("Test");
	
	// Copy the value in
	var message = new capnp.Message();
	let settingString = message.initRoot(Structures.AString);
	settingString.setValue(value);
	
	settingValue.setValue(settingString);
	
}

function BuildDeep(): void
{
	let messages: capnp.Message[] = [];
	let objects: Structures.Setting[] = [];

	let count = 10;
	console.log("Creating",count,"settings");
	for(let i=0;i<count;i++)
	{
		var message = new capnp.Message();
		let setting = message.initRoot(Structures.Setting);
		
		setting.setName("Hello");
		setting.setCategory("Cat");
		setting.setReadOnly(false);
		
		let someTestValue = "Hello World " + i.toString();
		SetSettingValue(setting,someTestValue);
		
		messages.push(message);
		objects.push(setting);
	}

	var message = new capnp.Message();
	let mainContainer = message.initRoot(Structures.StructContainer);

	console.log("Calling SerialiseStructListContainer()");
	SerialiseStructListContainer(mainContainer, objects);
	console.log("Done");
}

The error is thrown when setValue is called at the top level to set the Value of the outer struct to the container struct. This is the callstack and line it throws at:

image

The byteOffset is always 8 bytes greater than segment.byteLength. I wondered if this was something to do with the extra layer of objects and the required size of not being reported correctly to copy into the parent buffer.

I've attached an example project that reproduces the problem. After running npm install then ./build the output should be in the dist folder. The index.html page doesn't display anything, you'll need to check the console.

Any help would be greatly appreciated.

listofstructs.tar.gz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant