How to implement indented display trait for struct or enum

I have this enum which can store points as well as list of points.

pub enum Point {
    List(Option<Vec<Point>>),
    Point2D(Option<Box<[i32; 2]>>),
    Point3D(Option<Box<[i32; 3]>>),
}

I want to implement display trait, also it should with indentation like this.

List[
    Point2D[1, 2]
    Point3D[3, 4, 5]
    List[
        Point2D[6, 7]
        Point3D[8, 9, 10]
        List[
            Point2D[11, 12]
            Point3D[13, 14, 15]
        ]
    ]
]

The rust playground link

use std::fmt::{self, Display};

pub enum Point {
    List(Option<Vec<Point>>),
    Point2D(Option<Box<[i32; 2]>>),
    Point3D(Option<Box<[i32; 3]>>),
}

impl Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Point::List(Some(points)) => {
                let mut res = String::new();
                res.push_str("List[\n");
                for point in points {
                    res.push_str(&point.to_string());
                    res.push_str("\n");
                }
                res.push_str("]");
                write!(f, "{}", res)
            }
            Point::Point2D(Some(point)) => write!(f, "Point2D[{}, {}]", point[0], point[1]),
            Point::Point3D(Some(point)) => {
                write!(f, "Point3D[{}, {}, {}]", point[0], point[1], point[2])
            }
            _ => write!(f, "None"),
        }
    }
}

/*
List[
    Point2D[1, 2]
    Point3D[3, 4, 5]
    List[
        Point2D[6, 7]
        Point3D[8, 9, 10]
        List[
            Point2D[11, 12]
            Point3D[13, 14, 15]
        ]
    ]
]
*/

fn main() {
    let point = Point::List(Some(vec![
        Point::Point2D(Some(Box::new([1, 2]))),
        Point::Point3D(Some(Box::new([3, 4, 5]))),
        Point::List(Some(vec![
            Point::Point2D(Some(Box::new([6, 7]))),
            Point::Point3D(Some(Box::new([8, 9, 10]))),
            Point::List(Some(vec![
                Point::Point2D(Some(Box::new([11, 12]))),
                Point::Point3D(Some(Box::new([13, 14, 15]))),
            ])),
        ])),
    ]));

    println!("{}", point);
}

fmt::Formatter has helper methods to implement this sort of thing for Debug implementations. You could use a newtype to wrap your Display-implementing types in such a way that they use the Display implementation for Debug output, and then use that in combination with the helpers.

Then you can get indended output when you use the "alternative" format ("{:#}").

2 Likes