Skip to content

Commit a9fd6bb

Browse files
authored
Merge pull request #27 from mattatz/develop
Serialization features
2 parents e54c370 + 7033cdb commit a9fd6bb

File tree

5 files changed

+130
-2
lines changed

5 files changed

+130
-2
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "curvo"
3-
version = "0.1.30"
3+
version = "0.1.31"
44
authors = ["Masatatsu Nakamura <[email protected]"]
55
edition = "2021"
66
keywords = ["nurbs", "modeling", "graphics", "3d"]

src/region/compound_curve.rs

+116
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,119 @@ where
273273
self.spans.reverse();
274274
}
275275
}
276+
277+
#[cfg(feature = "serde")]
278+
impl<T, D: DimName> serde::Serialize for CompoundCurve<T, D>
279+
where
280+
T: FloatingPoint + serde::Serialize,
281+
DefaultAllocator: Allocator<D>,
282+
<DefaultAllocator as nalgebra::allocator::Allocator<D>>::Buffer<T>: serde::Serialize,
283+
{
284+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
285+
where
286+
S: serde::Serializer,
287+
{
288+
use serde::ser::SerializeStruct;
289+
let mut state = serializer.serialize_struct("CompoundCurve", 1)?;
290+
state.serialize_field("spans", &self.spans)?;
291+
state.end()
292+
}
293+
}
294+
295+
#[cfg(feature = "serde")]
296+
impl<'de, T, D: DimName> serde::Deserialize<'de> for CompoundCurve<T, D>
297+
where
298+
T: FloatingPoint + serde::Deserialize<'de>,
299+
DefaultAllocator: Allocator<D>,
300+
<DefaultAllocator as nalgebra::allocator::Allocator<D>>::Buffer<T>: serde::Deserialize<'de>,
301+
{
302+
fn deserialize<S>(deserializer: S) -> Result<Self, S::Error>
303+
where
304+
S: serde::Deserializer<'de>,
305+
{
306+
use serde::de::{self, MapAccess, Visitor};
307+
308+
#[derive(Debug)]
309+
enum Field {
310+
Spans,
311+
}
312+
313+
impl<'de> serde::Deserialize<'de> for Field {
314+
fn deserialize<S>(deserializer: S) -> Result<Self, S::Error>
315+
where
316+
S: serde::Deserializer<'de>,
317+
{
318+
struct FieldVisitor;
319+
320+
impl<'de> Visitor<'de> for FieldVisitor {
321+
type Value = Field;
322+
323+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
324+
formatter.write_str("`control_points` or `degree` or `knots`")
325+
}
326+
327+
fn visit_str<E>(self, value: &str) -> Result<Field, E>
328+
where
329+
E: de::Error,
330+
{
331+
match value {
332+
"spans" => Ok(Field::Spans),
333+
_ => Err(de::Error::unknown_field(value, FIELDS)),
334+
}
335+
}
336+
}
337+
338+
deserializer.deserialize_identifier(FieldVisitor)
339+
}
340+
}
341+
342+
struct CompoundCurveVisitor<T, D>(std::marker::PhantomData<(T, D)>);
343+
344+
impl<T, D> CompoundCurveVisitor<T, D> {
345+
pub fn new() -> Self {
346+
CompoundCurveVisitor(std::marker::PhantomData)
347+
}
348+
}
349+
350+
impl<'de, T, D: DimName> Visitor<'de> for CompoundCurveVisitor<T, D>
351+
where
352+
T: FloatingPoint + serde::Deserialize<'de>,
353+
DefaultAllocator: Allocator<D>,
354+
<DefaultAllocator as nalgebra::allocator::Allocator<D>>::Buffer<T>:
355+
serde::Deserialize<'de>,
356+
{
357+
type Value = CompoundCurve<T, D>;
358+
359+
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
360+
formatter.write_str("struct CompoundCurve")
361+
}
362+
363+
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
364+
where
365+
V: MapAccess<'de>,
366+
{
367+
let mut spans = None;
368+
while let Some(key) = map.next_key()? {
369+
match key {
370+
Field::Spans => {
371+
if spans.is_some() {
372+
return Err(de::Error::duplicate_field("spans"));
373+
}
374+
spans = Some(map.next_value()?);
375+
}
376+
}
377+
}
378+
let spans = spans.ok_or_else(|| de::Error::missing_field("spans"))?;
379+
380+
Ok(Self::Value { spans })
381+
}
382+
}
383+
384+
const FIELDS: &[&str] = &["spans"];
385+
deserializer.deserialize_struct(
386+
"CompoundCurve",
387+
FIELDS,
388+
CompoundCurveVisitor::<T, D>::new(),
389+
)
390+
}
391+
}

src/region/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010

1111
/// A closed region bounded by a single exterior curve and zero or more interior curves.
1212
#[derive(Clone, Debug, PartialEq)]
13+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1314
pub struct Region<T: FloatingPoint> {
1415
exterior: CompoundCurve<T, Const<3>>,
1516
interiors: Vec<CompoundCurve<T, Const<3>>>,

tests/serialize.rs

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use nalgebra::{Point3, Vector3};
77
#[test]
88
#[cfg(feature = "serde")]
99
fn test_curve_serialization() {
10+
use curvo::prelude::CompoundCurve;
11+
use nalgebra::{U3, U4};
12+
1013
let curve =
1114
NurbsCurve3D::try_circle(&Point3::origin(), &Vector3::x(), &Vector3::y(), 1.).unwrap();
1215
let json = serde_json::to_string_pretty(&curve).unwrap();
@@ -26,6 +29,14 @@ fn test_curve_serialization() {
2629
);
2730
assert_eq!(curve.degree(), der.degree());
2831
assert_relative_eq!(curve.knots().as_slice(), der.knots().as_slice());
32+
33+
let compound = CompoundCurve::new(vec![curve.clone()]);
34+
let json = serde_json::to_string_pretty(&compound).unwrap();
35+
let der: CompoundCurve<f64, U4> = serde_json::from_str(&json).unwrap();
36+
compound.spans().iter().enumerate().for_each(|(i, span)| {
37+
let o = &der.spans()[i];
38+
assert_relative_eq!(span.knots().as_slice(), o.knots().as_slice());
39+
});
2940
}
3041

3142
#[test]

0 commit comments

Comments
 (0)