Skip to content

Add trait implementations for Rational and SRational#553

Open
Compizfox wants to merge 5 commits into
dnglab:mainfrom
Compizfox:main
Open

Add trait implementations for Rational and SRational#553
Compizfox wants to merge 5 commits into
dnglab:mainfrom
Compizfox:main

Conversation

@Compizfox

@Compizfox Compizfox commented Jul 6, 2025

Copy link
Copy Markdown

This PR adds implementations for:

  • as_f32 for SRational (it was already there for Rational)
  • Add and Sum for Rational and SRational

I also considered simply using Ratio from the num-rational crate instead, as that crate already provides these implementations for these operations (and much more) out-of-the-box. That still might be a better long-term solution (preventing re-inventing the wheel), but that created some other conflicts with the rest of dnglab/rawler code using Rational/SRational that turned out less trivial to solve than I had hoped ;)

@cytrinox

cytrinox commented Jul 6, 2025

Copy link
Copy Markdown
Contributor

Thanks for the PR.
Could you please add simple test cases that uses these trait implementations? As the impls are not used by rawler itself, a test case would prevent unintentional deletion during code refactorings.

@Compizfox

Copy link
Copy Markdown
Author

Thanks for the PR. Could you please add simple test cases that uses these trait implementations? As the impls are not used by rawler itself, a test case would prevent unintentional deletion during code refactorings.

Sure, I just did so, and in the process realized that I only implemented Sum/Add for owned types, and not for references.

It gets a bit verbose implementing Add for all four combinations (per type), so I opted to use the handy macro from impl_ops.

In fact, I think I see some further opportunities for reducing code duplication for the Rational/SRational types, so if you're open to that, I can give it a go to re-use some code with generics.

@cytrinox cytrinox self-assigned this Jul 19, 2025
@cytrinox cytrinox added this to the 0.8.0 milestone Jul 19, 2025
@cytrinox cytrinox added the enhancement New feature or request label Jul 19, 2025
@cytrinox

Copy link
Copy Markdown
Contributor

As I stumbled myself over the lack of some Rational/SRational features, I agree that the num-rational crate is more straightforward. Do you want to take the opportunity to switch to num crate?
I've already required it in this commit: 54f5228#diff-467699101b2624e830efda4e5139615b26376ef7f70ae09c2f92672464bb0283

But this whole shitty code needs some refactoring 😞

@Compizfox

Copy link
Copy Markdown
Author

Sure, I'll take another stab at it!

I did try to simply substitute num-rational's Ratio, i.e. the following type aliases:

type Rational = Ratio<u32>;
type SRational = Ratio<i32>;

but the issue I ran into is all the TryFrom implementations that Ratio doesn't provide (and I can't implement either due to the orphan rule). I'll see if there's an easy way to deal with that, but maybe all the code that expects those implementations needs to be adapted.

@Compizfox

Copy link
Copy Markdown
Author

OK, so the major issues are:

  • Many code using BlackLevel in rawimage.rs expect a From<u16> implementation (for Ratio<u32>) to exist (all the raw decoders, i.e.:
    error[E0277]: the trait bound `Ratio<u32>: From<u16>` is not satisfied
       --> rawler/src/decoders/cr2.rs:574:47
        |
    574 |           1 => return Ok(Some(BlackLevel::new(&blacklevel, cam.cfa.width, cam.cfa.height, cpp))),
        |                               --------------- ^^^^^^^^^^^ the trait `From<u16>` is not implemented for `Ratio<u32>`
        |                               |
        |                               required by a bound introduced by this call
        |
        = help: the following other types implement trait `From<T>`:
                  `Ratio<T>` implements `From<(T, T)>`
                  `Ratio<T>` implements `From<T>`
        = note: required for `u16` to implement `Into<Ratio<u32>>`
    n
    
    (this occurs in some other places for some other integer types as well)
  • Ratio has a to_f32() method, but it returns an Option<f32>. It's not exactly clear to me in which cases this fails (the documentation says overflows map to -Inf/+Inf, and "None is returned if the value cannot be represented by an f32.". Not sure in what case it cannot be represented. Maybe we can just unwrap the result?
    error[E0308]: mismatched types
       --> rawler/src/rawimage.rs:123:9
        |
    123 |         self.levels[0].to_f32(),
        |         ^^^^^^^^^^^^^^^^^^^^^^^ expected `f32`, found `Option<f32>`
    

@cytrinox

Copy link
Copy Markdown
Contributor

OK, so the major issues are:

* Many code using `BlackLevel` in `rawimage.rs` expect a `From<u16>` implementation (for `Ratio<u32>`) to exist (all the raw decoders

The signature is something like:

  pub fn new<T>(levels: &[T], width: usize, height: usize, cpp: usize) -> Self
  where
    T: Copy + Into<Rational>,

Afaik there are traits in num-traits to write it like T: Copy + AsF32 and u16 would have an implementation for that.

* `Ratio` has a `to_f32()` method, but it returns an `Option<f32>`. It's not exactly clear to me in which cases this fails ([the documentation](https://docs.rs/num-rational/latest/num_rational/struct.Ratio.html#method.to_f32) says overflows map to -Inf/+Inf, and "None is returned if the value cannot be represented by an f32.". Not sure in what case it cannot be represented. Maybe we can just unwrap the result?

For now, I would use unwrap_or() and return NaN in such cases.

@Compizfox

Compizfox commented Jul 22, 2025

Copy link
Copy Markdown
Author

The signature is something like:

  pub fn new<T>(levels: &[T], width: usize, height: usize, cpp: usize) -> Self
  where
    T: Copy + Into<Rational>,

Afaik there are traits in num-traits to write it like T: Copy + AsF32 and u16 would have an implementation for that.

Okay, but the BlackLevel struct actually does hold a Vec<Rational>, though:

pub struct BlackLevel {
  pub levels: Vec<Rational>,

(not exactly sure why it's a Rational instead of just an integer, to be honest)

So unless I'm missing something, it actually needs Into<Rational>.

For now, I would use unwrap_or() and return NaN in such cases.

That sounds reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants