Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Surface.create_similar() should return a Result #251

Closed
federicomenaquintero opened this issue Mar 14, 2019 · 11 comments · Fixed by #287
Closed

Surface.create_similar() should return a Result #251

federicomenaquintero opened this issue Mar 14, 2019 · 11 comments · Fixed by #287

Comments

@federicomenaquintero
Copy link
Contributor

As in #141, cairo_surface_create_similar() will never return NULL, but it may return a cairo_surface_t * with an error status. I think Surface::create_similar() should return a Result<Surface, Status>.

@sdroege
Copy link
Member

sdroege commented Mar 15, 2019

Yes, and probably the same for various other functions. Someone should go through them all at some point.

@EPashkin
Copy link
Member

@federicomenaquintero Thanks for fixing
👍

@sdroege
Copy link
Member

sdroege commented Mar 19, 2019

@federicomenaquintero Thanks for fixing

This one is not fixed yet :)

@federicomenaquintero
Copy link
Contributor Author

Damn, just got a librsvg bug where we panicked because Surface.create_similar() always returns a Surface 😞

I've started fixing this. My first cut is to turn Surface::from_raw_full() -> Result, just like we had ImageSurface::from_raw_full() -> Result. The fallout is not bad; it actually makes things like RecordingSurface::create() more correct; it returns an Option right now, but cairo_recording_surface_create() will never return NULL, just a surface in an error status.

I have a question about this:

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for Surface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> Surface {
        Self::from_raw_full(ptr).unwrap()
    }
}

This is.... wrong? Or did we ever discuss this - the unwrap() seems perilous?

federicomenaquintero added a commit to federicomenaquintero/cairo that referenced this issue Oct 9, 2019
…esult

Cairo's surface creation functions never return NULL; instead they
always return a surface, but it may be in an error state.  In gtk-rs#141 we
started making the binding functions return Result for this; some
returned the plain FooSurface type, some others Option<FooSurface>.

This makes the following functions return Result<FooSurface, Status>

  Surface::create_similar()
  Surface::create_similar_image()
  RecordingSurface::create()
  Device.surface_create()
  Device.surface_create_for_target()

The foundation for all of this is that Surface::from_raw_full() now
also returns Result<FooSurface, Status>.  This is to make things
consistent with ImageSurface::from_raw_full().  Analogously, we now
have RecordingSurface::from_raw_full() that also returns Result.

Fixes gtk-rs#251
@sdroege
Copy link
Member

sdroege commented Oct 10, 2019

This is.... wrong? Or did we ever discuss this - the unwrap() seems perilous?

That's correct. If all you want to have returned is a concrete value instead of an Option, then the only thing we can do here is to panic if we get NULL or it doesn't work otherwise.

The Option FromGlibXXX impls would do the right thing and not panic.

@EPashkin
Copy link
Member

And maybe better add function to Status that convert T to Option (near ensure_valid) and use it in your other functions

@sdroege
Copy link
Member

sdroege commented Oct 10, 2019

Result::ok() you mean?

@EPashkin
Copy link
Member

@sdroege No, I meant in function that must return Option.

@EPashkin
Copy link
Member

Oh, ignore this idea, I wrongly understand main issue

@EPashkin
Copy link
Member

Actually I thought about something like

impl Status {
    pub fn to_result<T>(self, obj: T) -> Result<T,Self> {
        if self == Status::Success {
            Ok(obj)
        } else {
            Err(self)
        }
    }
}

impl ImageSurface {
    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result<ImageSurface, Status> {
        let surface = Self::try_from(Surface::from_raw_full(ptr)).unwrap();
        surface.status().to_result(surface)
    }

maybe with

trait Statusable {
   fn status(&self);
   fn to_result(self) -> Result<Self, Status> {
       self.status().to_result(self)
   }

federicomenaquintero added a commit to federicomenaquintero/cairo that referenced this issue Oct 10, 2019
…esult

Cairo's surface creation functions never return NULL; instead they
always return a surface, but it may be in an error state.  In gtk-rs#141 we
started making the binding functions return Result for this; some
returned the plain FooSurface type, some others Option<FooSurface>.

This makes the following functions return Result<FooSurface, Status>

  Surface::create_similar()
  Surface::create_similar_image()

  Device.surface_create()
  Device.surface_create_for_target()
  PdfSurface::new()
  RecordingSurface::create()
  RecordingSurface::from_raw_full()
  SvgSurface::new()
  XCBSurface::create()
  XCBSurface::create_for_bitmap()
  XCBSurface::create_with_xrender_format()

  From macro for_stream_constructors!:
  *::for_stream()
  *::for_raw_stream()

The foundation for all of this is that Surface::from_raw_full() now
also returns Result<FooSurface, Status>.  This is to make things
consistent with ImageSurface::from_raw_full().  Analogously, we now
have RecordingSurface::from_raw_full() that also returns Result.

Fixes gtk-rs#251
@federicomenaquintero
Copy link
Contributor Author

@EPashkin I'm using your to_result() idea; thanks for that. The others are already handled by Surface.from_raw_full(), I think.

GuillaumeGomez added a commit that referenced this issue Nov 21, 2019
…lar-result

(#251): Surface::create_similar() and friends should return a Result
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants