How to re-calculate orientation vectors when one of them is being changed?

I want to implement a Unity-like API for my transforms, with the ability to set forward, right, up vectors directly and change object's rotation quaternion accordingly.

I got stuck at the math behind it, though. What algorithm should we use to change the other 2 vectors?

I feel that the function should have 2 if branches and check which of the other two vectors to use to compute a cross product with the new vector, to decide which vector to use as the first and which is the second, and vice-versa in another branch.

I came up with something like this so far:

void Transform::SetForward(const glm::vec3& v) {
mForward = glm::normalize(v);
if (abs(abs(glm::dot(mForward, mUp)) - 1.0f) <= 1e-5) {
// dot is either -1 or 1 (straight up or down)
mUp = glm::cross(mRight, mForward);
mRight = glm::cross(mForward, mUp);
}
else {
mRight = glm::cross(mForward, mUp);
mUp = glm::cross(mRight, mForward);
}
FixRotationQuat();
}

// The red axis of the transform in world space.
public Vector3 right {
get { return rotation * Vector3.right; }
set { rotation = Quaternion.FromToRotation(Vector3.right, value); } }

// The green axis of the transform in world space.
public Vector3 up {
get { return rotation * Vector3.up; }
set { rotation = Quaternion.FromToRotation(Vector3.up, value); } }

// The blue axis of the transform in world space.
public Vector3 forward {
get { return rotation * Vector3.forward; }
set { rotation = Quaternion.LookRotation(value); } }

You can see its approach is to completely disregard the current rotation and directions of the other basis vectors. If you take two objects rotated completely differently, then set the forward (or up, or right) vector on both of them to the same value, you'll get the same orientation from both of them.