Comments (8)
Hmm, okay, as an option this is a good idea.
With P/Invoke, do you import the whole static class? Like using static Devolutions.Picky.Native
?
from c2cs.
I do not import the whole static class like that, but I use it from the other wrapping safe classes like so:
using C2CS;
namespace Devolutions.Picky;
public static class Pem
{
public static Pem Parse(String input) {
int inputSz = input.Length;
CStringU8 cInput = new CStringU8(input);
unsafe {
// `Native` is in the same namespace
Native.picky_pem_t *pem = Native.picky_pem_parse(cInput, inputSz);
// … build a `Pem` object…
}
}
…
}
The user will simply use the safe wrapper Devolutions.Picky.Pem
(and others), but may also use the low-level unsafe primitives from Devolutions.Picky.Native
if required.
from c2cs.
Oh, do you write some "safe" version of functions by hand?
from c2cs.
Yes, exactly!
from c2cs.
Okay, that's interesting. Do you think Is there room for improvement in terms of auto-generating code for "safe" version of the functions?
from c2cs.
Hmm… I'm not really sure as I hardly see how the safe code could be generated easily given an arbitrary C API.
Let's take this prototype that I have in my project:
/**
* Creates a PEM object with a copy of the data.
*/
struct picky_pem_t *picky_pem_new(const char *label,
int label_sz,
const uint8_t *data,
int data_sz);
Technically, I don't really need the label_sz
argument as long as label
is NULL-terminated, but, "better safe than sorry", I prefer to always specify the max size to read from the buffer.
So, I need to call the API with the following C# code:
// --- Pem.cs --- //
namespace Devolutions.Picky;
public class Pem
{
private unsafe Native.picky_pem_t* inner = null;
public Pem(String label, byte[] data)
{
byte[] utf8Label = Utils.StringToUtf8WithNulTerminator(label);
unsafe
{
fixed (byte* utf8LabelPtr = utf8Label, dataPtr = data)
{
this.inner = Native.Raw.pem_new(utf8LabelPtr, utf8Label.Length, dataPtr, data.Length);
if (this.inner == null)
{
throw new /* some exception */;
}
this.label = label;
this.data = data;
}
}
}
// --- cut --- //
}
My native library is working with UTF-8, so I convert with a helper class:
// --- Utils.cs --- //
using System.Text;
namespace Devolutions.Picky;
public static class Utils
{
public static byte[] StringToUtf8WithNulTerminator(String s)
{
int size = Encoding.UTF8.GetByteCount(s) + 1;
byte[] buf = new byte[size];
Encoding.UTF8.GetBytes(s, 0, s.Length, buf, 0);
buf[size - 1] = 0; // make sure we have a C-style nul-byte
return buf;
}
public static String Utf8WithNulTerminatorToString(byte[] utf8)
{
int size_without_nul = utf8.Length - 1;
char[] chars = new char[size_without_nul];
Encoding.UTF8.GetChars(utf8, 0, size_without_nul, chars, 0);
return new String(chars);
}
}
In the case of picky_pem_new
the special return value for an error is null
, but in other cases such as this one:
/**
* Copy the label associated to the data contained in the PEM object.
*
* Returns the number of bytes written, or `-1` if there was an error.
*/
int picky_pem_label(const struct picky_pem_t *this_, char *label, int label_sz);
The special value is -1
and calling code must handle the result accordingly.
Because it can't really be encoded in the C type system properly, this would require a way to convey to the generator:
- what is the special value to handle error cases,
- and what is the expected encoding of the strings.
I guess it's easier when binding directly a "higher-level" language such as C++ or Rust (like cxx
for Rust ↔ C++ or interoptopus
)
So, I think it's probably out of scope for C2CS
. I don't know if this helps haha
from c2cs.
Done in #49
from c2cs.
Looks good, thank you!
from c2cs.
Related Issues (20)
- Add new ref types for ref structs? HOT 1
- Bug if native strings are moved in memory HOT 7
- Ability to remap pointer types HOT 2
- Using custom code makes verification of code compile always fail HOT 2
- Some new C# features do not work in Unity HOT 1
- Re-write from scratch using TDD
- Support .NET Framework 4.8 HOT 1
- Eh it is sometime errors :( HOT 5
- Add option to disable C# 10 features (e.g. global usings) HOT 2
- Invalid code generated for static constants of int enum types HOT 3
- Improve type aliases for function pointers HOT 2
- Declare structs as partial HOT 2
- Add option to declare types outside of class HOT 1
- generated code not compiling due to missing cast to an enum HOT 8
- Anonymous fields not used HOT 7
- Automate bindings for Objective C HOT 1
- Multi-pass: C Locations
- How to use StringBuilder for char* used as output HOT 10
- Reduce noise of changes of generated C# in Git log HOT 9
- Not external function
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from c2cs.