Implementing Option<> for Custom Type

I would like to implement Option for a custom struct.

pub struct NodeId {
    index: u32,

impl NodeId {
    pub fn new() -> NodeId {
        NodeId {
            index: std::u32::MAX

    pub fn is_valid(&self) -> bool {
        self.index != std::u32::MAX

The idea is to reserve the value std::u32::MAX as None. This is how I do it in C++, but for Rust I would like to make use of Option<>.

Any ideas?

I don't understand what you mean by "implementing Option for a type". Option is not a trait, it's a (generic) type, "implementing it for a type" doesn't really make sense.

If you want to store a u32 value and indicate that is absent by using the maximal value, you can write a newtype wrapper around u32 and convert it to and from Option<u32>, e.g.

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MaybeU32(u32);

impl MaybeU32 {
    pub fn from_u32(inner: u32) -> Self {

    pub fn to_opt_u32(self) -> Option<u32> {
        if self.0 == u32::MAX {
        } else {

But it's hard to tell what exactly you want without some context regarding how you will use this type.

Sorry that my explaination is unclear, i am new to Rust.

What I want to do is to implement a Tree in Rust, and I would like to use indices to address the nodes in the tree.

pub struct Node {
    pub parent: Option<NodeId>,

Option would use 8 instead of 4 bytes.

I would like to extend Option so, that it would check if NodeId::index equals std::u32::MAX instead of reserving 4 extra bytes, but I dont know if its possible.

I don't think so, not like that. You could try using 0 as the absent value though, then representing node IDs with Option<NonZero<u32>>, which would also avoid storing a separate discriminant.


You don't get to change Option as it is only dealt with by the compiler.
There is optional crate that might offer what your after.

Option is literally just a regular enum:

pub enum Option<T> {

It's not a language feature. It's not something you can customize, because it's just a dumb regular type.

There's nothing stopping you from using std::u32::MAX as a placeholder value just based on convention like you would in C++.

An alternative is to use Option combined with std::num::NonZeroU32 and friends as @H2CO3 said. That way you get a type-safe wrapper which will make sure you handle placeholder values, while still having the same size as a normal u32.

use std::mem;
use std::num::NonZeroU32;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NodeId(Option<NonZeroU32>);

impl NodeId {
    pub const PLACEHOLDER: NodeId = NodeId(None);

    pub fn new(n: u32) -> Self {

    pub fn is_valid(&self) -> bool {

impl Default for NodeId {
    fn default() -> NodeId {

fn main() {
    assert_eq!(mem::size_of::<NodeId>(), mem::size_of::<u32>());