Skip to main content

fory_core/serializer/
unknown_case.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::context::{ReadContext, WriteContext};
19use crate::error::Error;
20use crate::resolver::{RefFlag, RefMode};
21use crate::serializer::any::check_erased_any_payload_type;
22use crate::serializer::{ForyDefault, Serializer};
23use crate::type_id::{self, TypeId};
24use crate::types::UnknownCase;
25use std::any::Any;
26use std::sync::Arc;
27
28#[doc(hidden)]
29pub fn write_payload(context: &mut WriteContext, unknown: &UnknownCase) -> Result<(), Error> {
30    if write_typed_payload(context, unknown)? {
31        return Ok(());
32    }
33    unknown
34        .value_arc()
35        .fory_write(context, RefMode::Tracking, true, false)
36}
37
38fn write_typed_payload(context: &mut WriteContext, unknown: &UnknownCase) -> Result<bool, Error> {
39    let type_id = unknown.type_id();
40    if type_id == type_id::UNKNOWN && unknown.downcast_ref::<()>().is_some() {
41        context.writer.write_i8(RefFlag::Null as i8);
42        return Ok(true);
43    }
44    if !has_typed_value(unknown) {
45        return Ok(false);
46    }
47    // UnknownCase carriers intentionally keep only a wire type id plus the
48    // polymorphic value. For internal numeric ids, the id byte is the complete
49    // Any type metadata. Scalar Any payloads are not ref-tracked, so their ref
50    // metadata is always NotNullValue before the original numeric encoding.
51    // Other types fall back to the normal Arc<dyn Any + Send + Sync> path.
52    context.writer.write_i8(RefFlag::NotNullValue as i8);
53    context.writer.write_u8(type_id as u8);
54    match type_id {
55        type_id::BOOL => context
56            .writer
57            .write_bool(*unknown.downcast_ref::<bool>().unwrap()),
58        type_id::INT8 => context
59            .writer
60            .write_i8(*unknown.downcast_ref::<i8>().unwrap()),
61        type_id::INT16 => context
62            .writer
63            .write_i16(*unknown.downcast_ref::<i16>().unwrap()),
64        type_id::INT32 => context
65            .writer
66            .write_i32(*unknown.downcast_ref::<i32>().unwrap()),
67        type_id::VARINT32 => context
68            .writer
69            .write_var_i32(*unknown.downcast_ref::<i32>().unwrap()),
70        type_id::INT64 => context
71            .writer
72            .write_i64(*unknown.downcast_ref::<i64>().unwrap()),
73        type_id::VARINT64 => context
74            .writer
75            .write_var_i64(*unknown.downcast_ref::<i64>().unwrap()),
76        type_id::TAGGED_INT64 => context
77            .writer
78            .write_tagged_i64(*unknown.downcast_ref::<i64>().unwrap()),
79        type_id::UINT8 => context
80            .writer
81            .write_u8(*unknown.downcast_ref::<u8>().unwrap()),
82        type_id::UINT16 => context
83            .writer
84            .write_u16(*unknown.downcast_ref::<u16>().unwrap()),
85        type_id::UINT32 => context
86            .writer
87            .write_u32(*unknown.downcast_ref::<u32>().unwrap()),
88        type_id::VAR_UINT32 => context
89            .writer
90            .write_var_u32(*unknown.downcast_ref::<u32>().unwrap()),
91        type_id::UINT64 => context
92            .writer
93            .write_u64(*unknown.downcast_ref::<u64>().unwrap()),
94        type_id::VAR_UINT64 => context
95            .writer
96            .write_var_u64(*unknown.downcast_ref::<u64>().unwrap()),
97        type_id::TAGGED_UINT64 => context
98            .writer
99            .write_tagged_u64(*unknown.downcast_ref::<u64>().unwrap()),
100        _ => return Ok(false),
101    }
102    Ok(true)
103}
104
105fn has_typed_value(unknown: &UnknownCase) -> bool {
106    match unknown.type_id() {
107        type_id::BOOL => unknown.downcast_ref::<bool>().is_some(),
108        type_id::INT8 => unknown.downcast_ref::<i8>().is_some(),
109        type_id::INT16 => unknown.downcast_ref::<i16>().is_some(),
110        type_id::INT32 | type_id::VARINT32 => unknown.downcast_ref::<i32>().is_some(),
111        type_id::INT64 | type_id::VARINT64 | type_id::TAGGED_INT64 => {
112            unknown.downcast_ref::<i64>().is_some()
113        }
114        type_id::UINT8 => unknown.downcast_ref::<u8>().is_some(),
115        type_id::UINT16 => unknown.downcast_ref::<u16>().is_some(),
116        type_id::UINT32 | type_id::VAR_UINT32 => unknown.downcast_ref::<u32>().is_some(),
117        type_id::UINT64 | type_id::VAR_UINT64 | type_id::TAGGED_UINT64 => {
118            unknown.downcast_ref::<u64>().is_some()
119        }
120        _ => false,
121    }
122}
123
124#[doc(hidden)]
125pub fn read_payload(context: &mut ReadContext, case_id: u32) -> Result<UnknownCase, Error> {
126    let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
127    match ref_flag {
128        RefFlag::Null => Ok(UnknownCase::new(case_id, ())),
129        RefFlag::Ref => {
130            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
131            let value = context
132                .ref_reader
133                .get_arc_ref::<dyn std::any::Any + Send + Sync>(ref_id)
134                .ok_or_else(|| {
135                    Error::invalid_data(format!("UnknownCase ref {} not found", ref_id))
136                })?;
137            Ok(UnknownCase::from_runtime(
138                case_id,
139                TypeId::UNKNOWN as u32,
140                value,
141            ))
142        }
143        RefFlag::NotNullValue | RefFlag::RefValue => {
144            let ref_id = if matches!(ref_flag, RefFlag::RefValue) {
145                // The wire ref id belongs to the unknown payload itself. Reserve it
146                // before reading nested payload fields so their own refs keep the
147                // same ids written by the normal reference engine.
148                Some(context.ref_reader.reserve_ref_id())
149            } else {
150                None
151            };
152            // The unknown-case serializer owns only the union payload envelope. It must
153            // not add a depth frame here: the decoded Any value is not a new nesting
154            // boundary by itself, and real nested payload serializers perform their
155            // own depth checks.
156            let type_info = context.read_any_type_info()?;
157            check_erased_any_payload_type(&type_info)?;
158            let boxed = type_info
159                .get_harness()
160                .read_polymorphic_data_as_send_sync_any(context, &type_info)?;
161            let value: Arc<dyn std::any::Any + Send + Sync> = Arc::from(boxed);
162            if let Some(ref_id) = ref_id {
163                context.ref_reader.store_arc_ref_at(ref_id, value.clone());
164            }
165            Ok(UnknownCase::from_runtime(
166                case_id,
167                type_info.get_type_id() as u32,
168                value,
169            ))
170        }
171    }
172}
173
174impl ForyDefault for UnknownCase {
175    fn fory_default() -> Self {
176        UnknownCase::new(0, ())
177    }
178}
179
180impl Serializer for UnknownCase {
181    fn fory_write(
182        &self,
183        context: &mut WriteContext,
184        ref_mode: RefMode,
185        write_type_info: bool,
186        _has_generics: bool,
187    ) -> Result<(), Error> {
188        let _ = ref_mode;
189        let _ = write_type_info;
190        write_payload(context, self)
191    }
192
193    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
194        write_payload(context, self)
195    }
196
197    fn fory_read(
198        context: &mut ReadContext,
199        ref_mode: RefMode,
200        read_type_info: bool,
201    ) -> Result<Self, Error> {
202        let _ = ref_mode;
203        let _ = read_type_info;
204        read_payload(context, 0)
205    }
206
207    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
208        read_payload(context, 0)
209    }
210    fn fory_read_data_as_send_sync_any(
211        context: &mut ReadContext,
212    ) -> Result<Box<dyn Any + Send + Sync>, Error> {
213        Ok(crate::serializer::box_send_sync(read_payload(context, 0)?))
214    }
215
216    fn fory_get_type_id(_: &crate::resolver::TypeResolver) -> Result<TypeId, Error> {
217        Ok(TypeId::UNKNOWN)
218    }
219
220    fn fory_type_id_dyn(
221        &self,
222        _type_resolver: &crate::resolver::TypeResolver,
223    ) -> Result<TypeId, Error> {
224        Ok(TypeId::UNKNOWN)
225    }
226
227    fn fory_static_type_id() -> TypeId {
228        TypeId::UNKNOWN
229    }
230
231    fn as_any(&self) -> &dyn Any {
232        self
233    }
234}