I recently had the same problem and was able to solve it in the following way in Java (should work in most languages):
int useValue = value >> 31;
return value & ~useValue;
I needed it specifically for Integer so I used it in here. We do 31 signed bit-shifts to the right (because Java Integer have exactly 32 bits), which turns all bits into 1 if the value is negative, otherwise 0. Then we return a bitwise AND of our value and the complement of our bits. So a negative number will always return 0 because the complement of its right-shifted bits is always 0. Any value & 0 will always return 0. If our number is positive (or 0), then the complement of those bits will always be 1. Any value & 1 will just return the plain value.
You unfortunately need to know how many bits your value has for this work but it fulfills all other criteria that you mentioned.