Skip to main content

formally_support/
nominal.rs

1//
2// ::formally - the open-source formal methods toolchain
3//
4// Copyright (c) 2025 Nicola Gigante
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23//
24
25use derive_more::From;
26use std::{
27    fmt::{Debug, Formatter},
28    hash::{Hash, Hasher},
29    ops::Deref,
30};
31
32/// Smart pointer wrapper for identity-based equality comparisons and hashing
33///
34/// [Nominal] wraps a [Deref] object to implement [Eq] and [Hash] based on the *value of the
35/// reference* to the pointee, instead of its eventual [Eq] and [Hash] instances.
36///
37/// This means wrapping a pointer or reference in a [Nominal] makes it compare and hash based on its
38/// identity as an object instead of its value, which would be the default in Rust.
39///
40/// In `formally`, this is used in places where two objects with the same value must nevertheless
41/// be considered distinct, most prominently the `Declared` and `Defined` types in the `smt` crate.
42#[derive(Clone, Default, From)]
43#[from(T)]
44#[repr(transparent)]
45pub struct Nominal<T>(pub T);
46
47impl<T> Nominal<T> {
48    /// Turns the [Nominal] into its underlying object.
49    pub fn into_inner(self) -> T {
50        self.0
51    }
52}
53
54impl<T> AsRef<T> for Nominal<T> {
55    fn as_ref(&self) -> &T {
56        &self.0
57    }
58}
59
60impl<T: Debug> Debug for Nominal<T> {
61    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62        write!(f, "Nominal({:?})", self.0)
63    }
64}
65
66impl<T: Deref> Hash for Nominal<T> {
67    fn hash<H: Hasher>(&self, state: &mut H) {
68        let ptr = &*self.0 as *const T::Target;
69        ptr.hash(state)
70    }
71}
72
73impl<T: Deref> PartialEq for Nominal<T> {
74    fn eq(&self, other: &Self) -> bool {
75        let this = &*self.0 as *const T::Target;
76        let other = &*other.0 as *const T::Target;
77
78        std::ptr::eq(this, other)
79    }
80}
81
82impl<T: Deref> Eq for Nominal<T> {}
83
84impl<T> Deref for Nominal<T> {
85    type Target = T;
86
87    fn deref(&self) -> &T {
88        &self.0
89    }
90}