jacksondunstan / UnityNativeScripting

Unity Scripting in C++

Home Page:https://jacksondunstan.com/articles/3938

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

String support/improvements

JmgrArt opened this issue · comments

Hi. I saw in the project's readme that the generator does not support string yet. I have however added an abstract method taking a string parameter to the AbstractBaseBallScript class and have implemented it on the C++ side. All I missed was some way to get a const char * from a String, so I added a c_str() method to it, adding binding methods similar to Plugin::StringNew. This seem to work, and I managed to transfer a C# string from Unity to the C++ side. I am wondering however if I did the right thing and if this could break in some ways. What do you think?
By the way, would it be possible to add conversion from/to std::string to the String class? If you don't want to force people to use the C++ Standard Library you could add some CMake configuration option like USE_STL.

Hi @JmgrArt, the string class has been supported since the very beginning of the project. The README.md just says that string methods aren't supported. This is because the string type is hard-coded as opposed to being generated by the code generator. So there's currently no way to expose more functionality of the string type such as the Substring method. Some day I'd like to address this, but don't have a solid plan at the moment, just a vague hope that the code generator will become robust enough that string no longer needs to be hard-coded at all.

As for your question about getting the character contents of a string, there's no way to do this right now. That said, it'd be rather easy to create a function like this to copy out the characters to a C++ buffer. Here's one idea for the C# function:

public static class StringContents
{
	public static void GetChars(
		string str,
		IntPtr into,
		int index = 0,
		int len = -1)
	{
		int i = index;
		int off = index + index;
		int end = index + (len >= 0 ? len : str.Length);
		while (i < end)
		{
			Marshal.WriteInt16(into, off, str[i]);
			i++;
			off += 2;
		}
	}
}

Then you'd call this from C++ like this:

int16_t buf[1024];
System::String str("Hello, world!");
StringContents::GetChars(str, &buf);

The usual binding layer would apply here, but it can't currently handle this because there's no support yet for pointers or IntPtr in the project. Eventually there will be, and you'll be able to write and expose functions like this with the code generator. For now, I'd need to hard-code that like with the other parts of string, which I'd like to avoid since it'll hopefully all be replaced at some point when a more general solution for string is implemented.

As for std::string, it should be trivial to convert one to a C# string:

std::string cppStr("Hello, world!");
System::String csharpStr(cppStr.c_str());

As mentioned above, there's no way to perform the reverse of this point.

The same strategy of converting to a "C string" works for plenty of other C++ string types out there like std::string_view, std::wstring, QString, gstring, FbString, CString, and CsString. I think it's best that this project avoid adding support for all the various string types, many of which have surprisingly compelling arguments to adopt them, and instead simply support a pass-through pointer like const char* or const int16_t* to reduce complexity like additional CMake configuration and library dependencies.

Regarding your own implementation and whether you did "the right thing," I can't say for sure since I haven't seen it. As long as you're making a copy of the characters into a buffer provided by C++, it seems like you'll be fine.