Statically check that one of args is Some?

fn make_line(
    start: Position,
    end: impl Into<Option<Position>>,
    length: impl Into<Option<Length>>
) -> Line;

Is it possible to statically express, that one of optional args is mandatory? Now I can see only option in runtime panic:

fn make_line(
    start: Position,
    end: impl Into<Option<Position>>,
    length: impl Into<Option<Length>>)
 -> Line{
    let length = match end {
        None => match length {
            None => panic!("one of args has to be specipied!"),
            Some(x) => x,
        },
        Some(x) => x,
   };
}

You can use an enum:

enum EndArg {
    EndPosition(Position),
    Length(Length),
}

impl From<Position> for EndArg {
    fn from(pos: Position) -> EndArg {
        EndArg::EndPosition(pos)
    }
}
impl From<Length> for EndArg {
    fn from(len: Length) -> EndArg {
        EndArg::Length(len)
    }
}
fn make_line(
    start: Position,
    end: impl Into<EndArg>,
) -> Line;

This way, you can pass either a position or length.

1 Like

Actually, this is probably a better option:

trait GetLength {
    fn to_length(self, start: Position) -> Length;
}

impl GetLength for Position {
    fn to_length(self, start: Position) -> Length {
        self - start
    }
}

impl GetLength for Length {
    fn to_length(self, _start: Position) -> Length {
        self
    }
}
fn make_line(
    start: Position,
    end: impl GetLength,
) -> Line;
2 Likes

Maybe, thanks!

But something bothers me in implementing trait for an arbitrary argument... Have to test, what suits better. Thank You for help!

Of course, there's another option you should also consider:

fn make_line(start: Position, length: Length) -> Line {

Then if someone has two positions, they can just call it like this:

make_line(start, end - start)

This is a lot simpler than introducing new enums or traits.

1 Like