Sounds good to me. Also, if you want to automate the c bindings to some
degree, then you can look at https://github.com/EmbarkStudios/physx-rs for
inspiration. There's a talk in the readme with their c bindings builder.
Failing that, I'm fine with going through the legwork of making the c
interface.

If I may make a suggestion for the naming, I'd suggest more or less
following what OIIO does in C++. So, for example,
OIIO::ImageInput.open(...) would be OIIO_ImageInput_open(...) and
classes/structs would be OIIOImageInput.

The only question I have at the moment is how do we want to handle naming
functions with overrides?

On Mon., Oct. 19, 2020, 1:00 p.m. Anders Langlands, <
[email protected]> wrote:

> Branching this thread to talk specifics...
>
> So to summarize the different approaches we've each taken, in my repo (
> https://github.com/anderslanglands/oiio-rs/tree/master/coiio) I have a
> small shim library that creates a C interface to OIIO by wrapping with
> functions like:
>
> ImageBuf ImageBuf_create(const char* filename) {
>     return new OIIO::ImageBuf(OIIO::string_view(filename));
> }
>
> When building the rust crate, this is compiled into a static library by
> Cargo using CMake, with the environment variable OIIO_ROOT specifying the
> path to the OIIO installation. Currently the build script errors out if
> OIIO_ROOT is not specified, but it would be trivial to have it default to
> /usr/local etc. I also at one point had it downloading OIIO and building it
> directly, but cmake-rs had some issues with always rebuilding OIIO on any
> change to the crate, which made development interminable, so I stripped
> that out. That was nearly two years ago so may have been fixed. A good
> alternative would be to provide a separate (bash or python) build script
> that would download deps and run the build manually as a pre-process.
>
> From what I can tell from Scott's repo, cxx is doing essentially the same
> thing, but cxx handles building the shim library internally, so there's no
> need for invoking CMake from build.rs. Presumably you'd still need to
> specify the path to (and potentially build) OIIO and its deps using this
> method. If you compare the code in Scott's repo to mine, you can see
> they're very similar indeed.
>
> The issue I see here is that I don't think cxx actually saves you
> anything. In fact there's *more* code in the cxx case because you're
> specifying both the implementation (ffi.cpp) and the interface (ffi.h),
> whereas I only have to specify the implementation (coiio.cpp) and the
> interface is declared solely in ffi.rs.
>
> Building and linking the static library is the easiest part of the
> process, and is also the part that would be more generally useful outside
> of just Rust - you could use that C interface to trivially bind any
> language you want, so I think we want to preserve that.
>
> That leaves the question of how do we generate the C interface in the
> first place. I've been doing it manually, which is a tedious process, but
> works. Since it's just calling the C++ directly I think it's also
> reasonably sturdy against changes to the underlying OIIO API, since the
> compiler should catch most misuses, although I'm sure there are plenty of
> opportunities for subtle bugs still. Not to mention bikeshedding about
> naming conventions and code styles :)
>
> My idea for how to make the binding generation more automatic was to try
> and leverage libclang to generate the C wrappers semi-automatically. This
> would still require a fair amount of code: first writing the binding
> generator, then writing the rules for how to wrap the C++ API, but should
> allow generating the C API automatically, rather than maintaining it
> manually for every release. The downside is obviously this tool doesn't
> exist yet, and it would add a (optional) dependency on clang to the project.
>
> I think the best course of action here would be to write a C wrapper in
> OIIO itself that could be maintained along with the rest of the project.
> This would build a little C99 library that could be installed alongside the
> C++ library. This would unfortunately mean manually writing a header to go
> with it, although that part could probably be automated with a little
> scripting.
>
> Then oiio-rs should be a completely separate Rust crate that just uses
> bindgen to generate the unsafe API from the C library automatically, and
> provides a safe API on top of that. (Larry - Rust/Cargo kinda assumes that
> Cargo is the thing doing all the building and dependency management, so
> trying to provide a Rust artefact from the OIIO build process would be
> painful if it's possible at all).
>
> Let me know what you think.
>
>
> Cheers,
> Anders
>
>
>
>
>
> On Tue, 20 Oct 2020 at 02:53, Alvaro Castaneda <[email protected]> wrote:
>
>> Hi Larry and Anders
>> I'm helping Scott with the Rust Wrapper.
>> using CXX is been good, it is a very manual process and makes it only
>> usable in Rust, Larry you mentioned a minimal C API, that would make it
>> much simpler to wrap to Rust, that would also mean in can be wrapped to
>> many other languages,
>> So far we didn't want to go the C route, but that might not be a bad
>> idea since it would open the library a lot more and it might make it
>> simpler to automate, at least the bulk of it, for Rust.
>>
>> We need to discuss the approach.
>>
>> On Sun, Oct 18, 2020 at 8:40 PM Anders Langlands <
>> [email protected]> wrote:
>>
>>> Hi Scott, yes please do add me to the repo I’d love to take a look and
>>> pitch in as time allows.
>>>
>>> On Mon, 19 Oct 2020 at 13:43, Scott Wilson <[email protected]>
>>> wrote:
>>>
>>>> Hey Anders,
>>>>
>>>> Cxx has so far been pretty okay. It's pretty manual (hopefully autocxx
>>>> makes it better, but as far as I know, it's still nowhere ready for using
>>>> it on OpenImageIO). Right now the process looks something like this:
>>>>
>>>> 1. Create a header/cpp file that contains all of your class methods as
>>>> functions.
>>>> 2. Create an unsafe Rust interferface that's a 1 to 1 copy of the C++
>>>> side.
>>>> 3. Create a safe Rust interface.
>>>>
>>>> For me, the really nice thing is I don't need to worry about the C++ ->
>>>> C -> Rust steps. It drops the C step, but I still need to write that C++
>>>> "ugly" interface.
>>>>
>>>> Also, if you want to join in on the fun, our repo is currently private
>>>> while we get things to a working state. But, I can add you to the repo.
>>>> Otherwise, I'm up for a discussion on how to take both designs and come up
>>>> with the best one.
>>>>
>>>> On Sun, Oct 18, 2020 at 4:51 PM Anders Langlands <
>>>> [email protected]> wrote:
>>>>
>>>>> Wrapping C in Rust is a two-stage process: first writing an "unsafe"
>>>>> FFI binding to the C API, which is usually almost completely automated 
>>>>> with
>>>>> a crate called bindgen, then writing a "safe" crate that provides a Rust-y
>>>>> API using the unsafe FFI bindings. Wrapping C++ means writing a C API
>>>>> first, then binding that to Rust, which is what my crate does.
>>>>>
>>>>> I've been meaning to return to this (and OSL, OpenSubdiv and others)
>>>>> at some point and try to make a project-specific C-binding generator using
>>>>> libclang, as manually maintaining the C stubs is laborious and 
>>>>> error-prone.
>>>>>
>>>>> Scott, I'd be curious to know how you're getting on with cxx, I've
>>>>> been meaning to look into that. I'd be happy to collaborate on something 
>>>>> we
>>>>> could integrate into the main project as Larry suggests.
>>>>>
>>>>> On Mon, 19 Oct 2020 at 12:30, Larry Gritz <[email protected]> wrote:
>>>>>
>>>>>> Feel free to have the discussion on-list, I'm sure it would be of
>>>>>> interest to many.
>>>>>>
>>>>>> If there was consensus on what the Rust APIs should look like, I
>>>>>> would welcome adding a set of Rust bindings to the main OIIO 
>>>>>> distribution.
>>>>>> Assuming that makes sense, I was thinking it would be much like we now 
>>>>>> have
>>>>>> with the Python bindings. The advantage to making Rust bindings part of 
>>>>>> the
>>>>>> main build would be that it could be built and tested as part of our CI,
>>>>>> versioned along with the rest of OIIO, and essentially never allowed to
>>>>>> break. Also, just like we would never accept a PR that added C++
>>>>>> functionality without making sure the Python bindings kept up, we could
>>>>>> ensure that nothing is left out of the Rust bindings. While I can
>>>>>> appreciate the cleanliness and independence of it being a separate 
>>>>>> project,
>>>>>> I can't help but think that it will be a neverending nightmare to try to
>>>>>> keep the bindings in sync with the main project.
>>>>>>
>>>>>> I don't know how automated it is to make Rust bindings for C (I know
>>>>>> it's a PITA for C++), but if making Rust bindings is substantially easier
>>>>>> if you had minimal plain C wrappers for the major C++ classes, I'm sure
>>>>>> there would be a lot of happy consumers of that even outside the Rust
>>>>>> interest group.
>>>>>>
>>>>>> I haven't had time to try Rust myself for any programming project,
>>>>>> though I've followed it from afar and like the idea of helping that
>>>>>> community. TBH, the main thing that keeps me from spending any time on 
>>>>>> Rust
>>>>>> is just that I can't contemplate the hassle of trying to program without 
>>>>>> my
>>>>>> favourite libraries, and having OIIO (and its many utilities that I reuse
>>>>>> in basically everything I write) available in Rust will substantially 
>>>>>> lower
>>>>>> the bar for me to dabble in it more.
>>>>>>
>>>>>> -- lg
>>>>>>
>>>>>>
>>>>>> On Oct 18, 2020, at 4:12 PM, Scott Wilson <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>> Hey Anders,
>>>>>>
>>>>>> We were inspired by what you did, and also decided to see if we can
>>>>>> take this in a slightly different direction/ use cxx. If you're 
>>>>>> interested
>>>>>> in discussing the wrapper more we can take it off the list.
>>>>>>
>>>>>> On Sun, Oct 18, 2020 at 3:35 PM Anders Langlands <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> I also have a rust binding here if you're interested:
>>>>>>> https://github.com/anderslanglands/oiio-rs
>>>>>>>
>>>>>>> On Sun, 18 Oct 2020 at 04:43, Scott Wilson <[email protected]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Awesome, thank you very much! I'll try this out and see how badly I
>>>>>>>> break things.
>>>>>>>>
>>>>>>>> On Sat., Oct. 17, 2020, 1:02 a.m. Larry Gritz, <[email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> If you know the true legal extent of the memory allocation in
>>>>>>>>> which that data pointer is located (in this case, the beginning and 
>>>>>>>>> ending
>>>>>>>>> of the vector, if you are passing a pointer to one of the elements of 
>>>>>>>>> that
>>>>>>>>> vector), then I think you could certainly consider it an error if any 
>>>>>>>>> of
>>>>>>>>> these addresses lay outside that buffer:
>>>>>>>>>
>>>>>>>>>     data + xstride*width - 1
>>>>>>>>>     data + ystride*height - 1
>>>>>>>>>     data + ystride*(height - 1) + xstride*width - 1
>>>>>>>>>     data + zstride*depth
>>>>>>>>>     data + zstride*(depth - 1) + ystride*height - 1
>>>>>>>>>     data + zstride*(depth - 1) + ystride*(height - 1) +
>>>>>>>>> xstride*width - 1
>>>>>>>>>
>>>>>>>>> There may be a more succinct way to put that, but I think it
>>>>>>>>> covers all the cases of + and - strides.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Oct 17, 2020, at 12:42 AM, Scott Wilson <[email protected]>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> Thanks! I guess to come from this at a different angle, let's say
>>>>>>>>> I'm doing something like this:
>>>>>>>>>
>>>>>>>>> std::vector<uint8_t> pixels(10*10*3*1);
>>>>>>>>> ImageInput.read_image(TypeDesc::UINT8, @pixels[0])
>>>>>>>>>
>>>>>>>>> Would there be a case where I could pick a stride value that would
>>>>>>>>> fall outside the pixels vector?
>>>>>>>>>
>>>>>>>>> PS: Thanks! I'm working on this with a friend, and hope to have
>>>>>>>>> something released in the near future.
>>>>>>>>>
>>>>>>>>> On Fri., Oct. 16, 2020, 11:47 p.m. Larry Gritz, <[email protected]>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>> Oops, my math was wrong (in an unimportant detail): If you are
>>>>>>>>>> making a mosaic of 16x5 of these 10x10 images, it is 80 small images 
>>>>>>>>>> you
>>>>>>>>>> are assembling in total, not 40.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Oct 16, 2020, at 11:43 PM, Larry Gritz <[email protected]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> The strides don't describe the size of the image, they are the
>>>>>>>>>> spacing in memory of where you want the values to be placed upon 
>>>>>>>>>> being read
>>>>>>>>>> (or taken from in order to write). There is no invalid set of 
>>>>>>>>>> strides,
>>>>>>>>>> because the caller might want them to end up anywhere in memory.
>>>>>>>>>>
>>>>>>>>>> Or am I misunderstanding?
>>>>>>>>>>
>>>>>>>>>> For a fully "contiguous" memory buffer where you intend for every
>>>>>>>>>> plane, scanline, pixel, and channel immediately follows the previous 
>>>>>>>>>> one,
>>>>>>>>>> then in our example the strides would be xstride=3, ystride=30,
>>>>>>>>>> zstride=300. (Though for a 2D image, the zstride is not used.)
>>>>>>>>>>
>>>>>>>>>> Here's an example of where you might have a stride range that is
>>>>>>>>>> wildly outside this: Let's say that you have 40 of these 10 x 10 x 3 
>>>>>>>>>> x
>>>>>>>>>> uint8 image files and you are trying to read them in and assemble 
>>>>>>>>>> them into
>>>>>>>>>> a single RGBA mosaic image of 16x5 x 4 x uint8 (the additional 
>>>>>>>>>> channel is
>>>>>>>>>> alpha, which you will separately fill in as 1.0 [or 255 uint8] 
>>>>>>>>>> because it's
>>>>>>>>>> not in your RGB files).  Here's a cartoon to illustrate this:
>>>>>>>>>>
>>>>>>>>>>   +-----------------------------------------+
>>>>>>>>>>   | | | | | | | | | | | | | | | | | | | | | |
>>>>>>>>>>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
>>>>>>>>>>   | | | | | | | | | | | | | | | | | | | | | |
>>>>>>>>>>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
>>>>>>>>>>   | | | | | | | | | |X| | | | | | | | | | | |
>>>>>>>>>>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
>>>>>>>>>>   | | | | | | | | | | | | | | | | | | | | | |
>>>>>>>>>>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
>>>>>>>>>>   | | | | | | | | | | | | | | | | | | | | | |
>>>>>>>>>>   +-----------------------------------------+
>>>>>>>>>>
>>>>>>>>>> Each of my little grid cells is a 10x10 image. But that 10x10
>>>>>>>>>> image denoted by the "X" needs to be placed in memory in the right 
>>>>>>>>>> portion
>>>>>>>>>> of the 16x10 x 5x10 mosaic. So what are the strides we use for the 
>>>>>>>>>> read?
>>>>>>>>>> Well, the xstride is 4 because we're making room for an alpha 
>>>>>>>>>> channel that
>>>>>>>>>> wasn't present in the file, the ystride is 640 (= 10*16*4), because 
>>>>>>>>>> each
>>>>>>>>>> scanline of the little 10x10 image that you read needs to be placed 
>>>>>>>>>> on the
>>>>>>>>>> proper scanline of the 160x50 mosaic you are assembling in memory.
>>>>>>>>>>
>>>>>>>>>> --  lg
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> P.S. Woo-hoo for making a Rust wrapper. I think that's a totally
>>>>>>>>>> great thing.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Oct 16, 2020, at 10:46 PM, Scott Wilson <[email protected]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> I'm experimenting with a Rust wrapper for OIIO, and had some
>>>>>>>>>> questions about the stride.
>>>>>>>>>>
>>>>>>>>>> Let's say I have an image that is 10x10 pixels, and 3 channels,
>>>>>>>>>> and 1 byte per channel. What strides would be invalid for that 
>>>>>>>>>> image? I'm
>>>>>>>>>> guessing that anything between -10 * 10 * 3 * 1 to 10 * 10 * 3 * 1 
>>>>>>>>>> and the
>>>>>>>>>> AutoStride would be valid, and everything else may try to access 
>>>>>>>>>> memory
>>>>>>>>>> that isn't initialized. Is this assumption correct, or am I missing
>>>>>>>>>> something?
>>>>>>>>>>
>>>>>>>>>> Thanks!
>>>>>>>>>> _______________________________________________
>>>>>>>>>> Oiio-dev mailing list
>>>>>>>>>> [email protected]
>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Larry Gritz
>>>>>>>>>> [email protected]
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> _______________________________________________
>>>>>>>>>> Oiio-dev mailing list
>>>>>>>>>> [email protected]
>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Larry Gritz
>>>>>>>>>> [email protected]
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> _______________________________________________
>>>>>>>>>> Oiio-dev mailing list
>>>>>>>>>> [email protected]
>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> Oiio-dev mailing list
>>>>>>>>> [email protected]
>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Larry Gritz
>>>>>>>>> [email protected]
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> Oiio-dev mailing list
>>>>>>>>> [email protected]
>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> Oiio-dev mailing list
>>>>>>>> [email protected]
>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> Oiio-dev mailing list
>>>>>>> [email protected]
>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>>
>>>>>> _______________________________________________
>>>>>> Oiio-dev mailing list
>>>>>> [email protected]
>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Larry Gritz
>>>>>> [email protected]
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> Oiio-dev mailing list
>>>>>> [email protected]
>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>>
>>>>> _______________________________________________
>>>>> Oiio-dev mailing list
>>>>> [email protected]
>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>>
>>>> _______________________________________________
>>>> Oiio-dev mailing list
>>>> [email protected]
>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>>
>>> _______________________________________________
>>> Oiio-dev mailing list
>>> [email protected]
>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>>
>> _______________________________________________
>> Oiio-dev mailing list
>> [email protected]
>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>>
> _______________________________________________
> Oiio-dev mailing list
> [email protected]
> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
>
_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

Reply via email to