nv_redfish_core/lib.rs
1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Core Redfish foundation library used by code generated from the CSDL compiler.
17//!
18//! Purpose
19//! - Serve as a dependency for autogenerated Redfish types produced by the CSDL compiler.
20//! - Provide semantic-unaware primitives that generated code relies on.
21//! - Avoid any knowledge of specific Redfish services, schemas, or OEM semantics.
22//!
23//! Scope (building blocks only)
24//! - Identity and metadata: [`ODataId`], [`ODataETag`]
25//! - EDM value wrappers: [`EdmDateTimeOffset`], [`EdmDuration`]
26//! - Navigation properties: [`NavProperty<T>`]
27//! - Generic operation traits: [`Creatable`], [`Updatable`], [`Deletable`]
28//! - Entity contracts: [`EntityTypeRef`], [`Expandable`]
29//! - Action envelope: [`Action<T, R>`]
30//! - Client abstraction: [`Bmc`] (transport-agnostic interface used by generated code)
31//!
32//! Non-goals
33//! - No service- or schema-specific models are defined here.
34//! - No business logic or policy decisions are embedded here.
35//! - No transport specification
36//!
37//! How generated code uses these primitives
38//! - Each generated entity struct implements [`EntityTypeRef`].
39//! - Navigation properties in generated code are wrapped in [`NavProperty<T>`].
40//! - Generated actions are represented as [`Action<T, R>`].
41//! - If the schema allows it, generated types implement [`Creatable`], [`Updatable`], and/or [`Deletable`]
42//! and route operations through a user-provided [`Bmc`] implementation.
43//!
44
45#![deny(
46 clippy::all,
47 clippy::pedantic,
48 clippy::nursery,
49 clippy::suspicious,
50 clippy::complexity,
51 clippy::perf
52)]
53#![deny(
54 clippy::absolute_paths,
55 clippy::todo,
56 clippy::unimplemented,
57 clippy::tests_outside_test_module,
58 clippy::panic,
59 clippy::unwrap_used,
60 clippy::unwrap_in_result,
61 clippy::unused_trait_names,
62 clippy::print_stdout,
63 clippy::print_stderr
64)]
65#![deny(missing_docs)]
66
67/// Action-related types.
68pub mod action;
69/// BMC trait and credentials.
70pub mod bmc;
71/// Custom deserialization helpers.
72pub mod deserialize;
73/// Dynamic properties support.
74pub mod dynamic_properties;
75/// `Edm.DateTimeOffset` type.
76pub mod edm_date_time_offset;
77/// `Edm.Duration` type.
78pub mod edm_duration;
79/// `Edm.PrimitiveType` type.
80pub mod edm_primitive_type;
81/// Navigation property wrapper.
82pub mod nav_property;
83/// Type for `@odata.id` identifier.
84pub mod odata;
85/// Support of redfish queries
86pub mod query;
87
88use crate::query::ExpandQuery;
89use futures_core::TryStream;
90use serde::{Deserialize, Serialize};
91use std::pin::Pin;
92use std::{future::Future, sync::Arc};
93
94#[doc(inline)]
95pub use action::Action;
96#[doc(inline)]
97pub use action::ActionError;
98#[doc(inline)]
99pub use bmc::Bmc;
100#[doc(inline)]
101pub use deserialize::de_optional_nullable;
102#[doc(inline)]
103pub use deserialize::de_required_nullable;
104#[doc(inline)]
105pub use dynamic_properties::DynamicProperties;
106#[doc(inline)]
107pub use edm_date_time_offset::EdmDateTimeOffset;
108#[doc(inline)]
109pub use edm_duration::EdmDuration;
110#[doc(inline)]
111pub use edm_primitive_type::EdmPrimitiveType;
112#[doc(inline)]
113pub use nav_property::NavProperty;
114#[doc(inline)]
115pub use nav_property::Reference;
116#[doc(inline)]
117pub use nav_property::ReferenceLeaf;
118#[doc(inline)]
119pub use odata::ODataETag;
120#[doc(inline)]
121pub use odata::ODataId;
122#[doc(inline)]
123pub use query::FilterQuery;
124#[doc(inline)]
125pub use query::ToFilterLiteral;
126#[doc(inline)]
127pub use serde_json::Value as AdditionalProperties;
128#[doc(inline)]
129pub use uuid::Uuid as EdmGuid;
130
131/// Entity type reference trait implemented by the CSDL compiler
132/// for all generated entity types and for all `NavProperty<T>` where
133/// `T` is a struct for an entity type.
134pub trait EntityTypeRef {
135 /// Value of `@odata.id` field of the Entity.
136 fn odata_id(&self) -> &ODataId;
137
138 /// Value of `@odata.etag` field of the Entity.
139 fn etag(&self) -> Option<&ODataETag>;
140
141 /// Refresh the entity by fetching it again from the BMC.
142 fn refresh<B: Bmc>(&self, bmc: &B) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send
143 where
144 Self: Sync + Send + 'static + Sized + for<'de> Deserialize<'de>,
145 {
146 bmc.get::<Self>(self.odata_id())
147 }
148}
149
150/// Defines entity types that support `$expand` via query parameters.
151pub trait Expandable:
152 EntityTypeRef + Send + Sync + Sized + 'static + for<'a> Deserialize<'a>
153{
154 /// Expand the entity according to the provided query.
155 fn expand<B: Bmc>(
156 &self,
157 bmc: &B,
158 query: ExpandQuery,
159 ) -> impl Future<Output = Result<Arc<Self>, B::Error>> + Send {
160 bmc.expand::<Self>(self.odata_id(), query)
161 }
162}
163
164/// Boxed fallible stream used by BMC streaming APIs.
165pub type BoxTryStream<T, E> =
166 Pin<Box<dyn TryStream<Ok = T, Error = E, Item = Result<T, E>> + Send>>;
167
168/// Outcome of a mutating Redfish operation that can complete asynchronously.
169#[derive(Debug)]
170pub struct AsyncTask {
171 /// Request completed successfully with no response body
172 pub id: ODataId,
173 /// The recommended number of seconds to wait before polling again
174 pub retry_after_secs: Option<u64>,
175}
176
177/// Outcome of a mutating Redfish operation.
178#[derive(Debug)]
179pub enum ModificationResponse<T> {
180 /// Request completed synchronously
181 Entity(T),
182 /// Requst completed asynchronously, with the provided `ODataId` to poll for completion
183 Task(AsyncTask),
184 /// Request completed successfully with no response body
185 Empty,
186}
187
188/// This trait is assigned to the collections that are marked as
189/// creatable in the CSDL specification.
190pub trait Creatable<V: Sync + Send + Serialize, R: Sync + Send + Sized + for<'de> Deserialize<'de>>:
191 EntityTypeRef + Sized
192{
193 /// Create an entity using `create` as payload.
194 fn create<B: Bmc>(
195 &self,
196 bmc: &B,
197 create: &V,
198 ) -> impl Future<Output = Result<ModificationResponse<R>, B::Error>> + Send {
199 bmc.create::<V, R>(self.odata_id(), create)
200 }
201}
202
203/// This trait is assigned to entity types that are marked as
204/// updatable in the CSDL specification.
205pub trait Updatable<V: Sync + Send + Serialize>: EntityTypeRef + Sized
206where
207 Self: Sync + Send + Sized + for<'de> Deserialize<'de>,
208{
209 /// Update an entity using `update` as payload.
210 fn update<B: Bmc>(
211 &self,
212 bmc: &B,
213 update: &V,
214 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
215 bmc.update::<V, Self>(self.odata_id(), self.etag(), update)
216 }
217}
218
219/// This trait is assigned to entity types that are marked as
220/// deletable in the CSDL specification.
221pub trait Deletable: EntityTypeRef + Sized + Sync + Send + for<'de> Deserialize<'de> {
222 /// Delete current entity.
223 fn delete<B: Bmc>(
224 &self,
225 bmc: &B,
226 ) -> impl Future<Output = Result<ModificationResponse<Self>, B::Error>> + Send {
227 bmc.delete::<Self>(self.odata_id())
228 }
229}
230
231/// This trait is assigned to updatable entity types to support
232/// @Redfish.Settings workflow.
233pub trait RedfishSettings<E: EntityTypeRef>: Sized {
234 /// Reference to the enity type object.
235 fn settings_object(&self) -> Option<NavProperty<E>>;
236}
237
238/// Trait for converting enum variants to `snake_case` strings
239pub trait ToSnakeCase {
240 /// Convert this enum variant to a `snake_case` string
241 fn to_snake_case(&self) -> &'static str;
242}
243
244/// Trait for types that can be used as filter properties in `OData` queries
245pub trait FilterProperty {
246 /// Returns the `OData` property path for this property
247 fn property_path(&self) -> &str;
248}