mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-03 20:50:12 +01:00
113 lines
4.2 KiB
C
113 lines
4.2 KiB
C
/*
|
|
* Copyright © 2025 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "util-macros.h"
|
|
|
|
/**
|
|
* This is a C version of the Rust newtypes in the
|
|
* form struct Foo(u32);
|
|
*
|
|
* Use: DECLARE_NEWTYPE(foo, int)
|
|
*
|
|
* Defines a single-value struct called foo_t
|
|
* with the following helper functions:
|
|
*
|
|
* - int foo_as_int(foo_t f);
|
|
* - int foo(foo f);
|
|
* - foo_t foo_from_int(int);
|
|
* - foo_t foo_copy(foo_t f);
|
|
* - foo_t foo_min(foo_t a, foo_t b);
|
|
* - foo_t foo_max(foo_t a, foo_t b);
|
|
* - int foo_cmp(foo_t a, foo_t b);
|
|
* - bool foo_eq(foo_t a, int b);
|
|
* - bool foo_ne(foo_t a, int b);
|
|
* - bool foo_le(foo_t a, int b);
|
|
* - bool foo_lt(foo_t a, int b);
|
|
* - bool foo_ge(foo_t a, int b);
|
|
* - bool foo_gt(foo_t a, int b);
|
|
*
|
|
* Since all the structs are single-value the provided functions don't
|
|
* use pointers but pass the struct around as value. The compiler
|
|
* hopefully optimizes things so this is the same as passing ints around
|
|
* but having some better type-safety.
|
|
*
|
|
* For example, this logic error is no longer possible using newtypes:
|
|
* ```
|
|
* double cm_to_inches(int cm) { return cm / 2.54; }
|
|
*
|
|
* struct person {
|
|
* int age;
|
|
* int height;
|
|
* };
|
|
* struct person p = { .age = 20, .height = 180 };
|
|
* double inches = cm_to_inches(p.age);
|
|
* ```
|
|
* With newtypes this would be:
|
|
* ```
|
|
* DECLARE_NEWTYPE(year, int);
|
|
* DECLARE_NEWTYPE(cm, int);
|
|
* DECLARE_NEWTYPE(in, double);
|
|
*
|
|
* in_t cm_to_inches(cm_t cm) { return in_from_double(cm_as_int(cm) / 2.54); }
|
|
*
|
|
* struct person {
|
|
* year_t age;
|
|
* cm_t height;
|
|
* };
|
|
* struct person p = { .age = year_from_int(20), .height = cm_from_int(180) };
|
|
* in_t inches = cm_to_inches(p.age); // Compiler error!
|
|
* in_t inches = cm_to_inches(p.height); // Yay
|
|
* ```
|
|
* And a side-effect is that the units are documented as part of the type.
|
|
*/
|
|
#define DECLARE_NEWTYPE(name_, type_) \
|
|
typedef struct { \
|
|
type_ v; \
|
|
} name_##_t; \
|
|
\
|
|
static inline name_##_t name_##_from_##type_(type_ v) { return (name_##_t) { .v = v }; }; \
|
|
static inline type_ name_##_as_##type_(name_##_t name_) { return name_.v; }; \
|
|
static inline type_ name_(name_##_t name_) { return name_##_as_##type_(name_); } \
|
|
static inline name_##_t name_##_copy(name_##_t name_) { return name_##_from_##type_(name_.v); }; \
|
|
static inline name_##_t name_##_min(name_##_t a, name_##_t b) { \
|
|
return name_##_from_##type_(min(a.v, b.v)); \
|
|
}; \
|
|
static inline name_##_t name_##_max(name_##_t a, name_##_t b) { \
|
|
return name_##_from_##type_(max(a.v, b.v)); \
|
|
}; \
|
|
static inline int name_##_cmp(name_##_t a, name_##_t b) { \
|
|
return a.v < b.v ? -1 : (a.v > b.v ? 1 : 0); \
|
|
}; \
|
|
static inline bool name_##_eq(name_##_t a, type_ b) { return a.v == b; }\
|
|
static inline bool name_##_ne(name_##_t a, type_ b) { return a.v != b; }\
|
|
static inline bool name_##_le(name_##_t a, type_ b) { return a.v <= b; }\
|
|
static inline bool name_##_lt(name_##_t a, type_ b) { return a.v < b; }\
|
|
static inline bool name_##_ge(name_##_t a, type_ b) { return a.v >= b; }\
|
|
static inline bool name_##_gt(name_##_t a, type_ b) { return a.v > b; }\
|
|
struct __useless_struct_to_allow_trailing_semicolon__
|