#include "../include/metadata.h" #include namespace feather { void Metadata::serialize(std::ostream& os) const { os.write(reinterpret_cast(×tamp), 8); os.write(reinterpret_cast(&importance), 4); uint8_t type_val = static_cast(type); os.write(reinterpret_cast(&type_val), 1); uint16_t source_len = static_cast(source.size()); os.write(reinterpret_cast(&source_len), 2); os.write(source.data(), source_len); uint32_t content_len = static_cast(content.size()); os.write(reinterpret_cast(&content_len), 4); os.write(content.data(), content_len); uint16_t tags_len = static_cast(tags_json.size()); os.write(reinterpret_cast(&tags_len), 2); os.write(tags_json.data(), tags_len); // Phase 3: Write 0 links (legacy slot — edges field replaces this in v5) // We write links_count=0 so v3/v4 readers see no plain links and don't crash. uint16_t links_count = 0; os.write(reinterpret_cast(&links_count), 2); os.write(reinterpret_cast(&recall_count), 4); os.write(reinterpret_cast(&last_recalled_at), 8); // Phase 4: namespace_id, entity_id, attributes uint16_t ns_len = static_cast(namespace_id.size()); os.write(reinterpret_cast(&ns_len), 2); os.write(namespace_id.data(), ns_len); uint16_t eid_len = static_cast(entity_id.size()); os.write(reinterpret_cast(&eid_len), 2); os.write(entity_id.data(), eid_len); uint16_t attr_count = static_cast(attributes.size()); os.write(reinterpret_cast(&attr_count), 2); for (const auto& [key, val] : attributes) { uint16_t key_len = static_cast(key.size()); os.write(reinterpret_cast(&key_len), 2); os.write(key.data(), key_len); uint32_t val_len = static_cast(val.size()); os.write(reinterpret_cast(&val_len), 4); os.write(val.data(), val_len); } // Phase 5: typed, weighted edges uint16_t edge_count = static_cast(edges.size()); os.write(reinterpret_cast(&edge_count), 2); for (const auto& e : edges) { os.write(reinterpret_cast(&e.target_id), 8); uint8_t rt_len = static_cast(std::min(e.rel_type.size(), size_t(255))); os.write(reinterpret_cast(&rt_len), 1); os.write(e.rel_type.data(), rt_len); os.write(reinterpret_cast(&e.weight), 4); } // Phase 6: ttl + confidence os.write(reinterpret_cast(&ttl), 8); os.write(reinterpret_cast(&confidence), 4); } Metadata Metadata::deserialize(std::istream& is) { Metadata m; is.read(reinterpret_cast(&m.timestamp), 8); is.read(reinterpret_cast(&m.importance), 4); uint8_t type_val; is.read(reinterpret_cast(&type_val), 1); m.type = static_cast(type_val); uint16_t source_len; is.read(reinterpret_cast(&source_len), 2); m.source.resize(source_len); is.read(&m.source[0], source_len); uint32_t content_len; is.read(reinterpret_cast(&content_len), 4); m.content.resize(content_len); is.read(&m.content[0], content_len); uint16_t tags_len; is.read(reinterpret_cast(&tags_len), 2); m.tags_json.resize(tags_len); is.read(&m.tags_json[0], tags_len); // Phase 3: legacy links slot (v3/v4 used this; v5 writes 0 here but reads edges below) uint16_t links_count = 0; if (!is.read(reinterpret_cast(&links_count), 2)) return m; if (links_count > 0) { // Old v3/v4 plain link IDs — promote to edges with default type/weight for (uint16_t i = 0; i < links_count; ++i) { uint64_t target; is.read(reinterpret_cast(&target), 8); m.edges.push_back({target, "related_to", 1.0f}); } } is.read(reinterpret_cast(&m.recall_count), 4); is.read(reinterpret_cast(&m.last_recalled_at), 8); // Phase 4: namespace_id, entity_id, attributes uint16_t ns_len = 0; if (!is.read(reinterpret_cast(&ns_len), 2)) return m; m.namespace_id.resize(ns_len); if (ns_len > 0) is.read(&m.namespace_id[0], ns_len); uint16_t eid_len = 0; is.read(reinterpret_cast(&eid_len), 2); m.entity_id.resize(eid_len); if (eid_len > 0) is.read(&m.entity_id[0], eid_len); uint16_t attr_count = 0; is.read(reinterpret_cast(&attr_count), 2); for (uint16_t i = 0; i < attr_count; ++i) { uint16_t key_len = 0; is.read(reinterpret_cast(&key_len), 2); std::string key(key_len, '\0'); if (key_len > 0) is.read(&key[0], key_len); uint32_t val_len = 0; is.read(reinterpret_cast(&val_len), 4); std::string val(val_len, '\0'); if (val_len > 0) is.read(&val[0], val_len); m.attributes[key] = val; } // Phase 5: typed, weighted edges uint16_t edge_count = 0; if (!is.read(reinterpret_cast(&edge_count), 2)) return m; for (uint16_t i = 0; i < edge_count; ++i) { Edge e; is.read(reinterpret_cast(&e.target_id), 8); uint8_t rt_len = 0; is.read(reinterpret_cast(&rt_len), 1); e.rel_type.resize(rt_len); if (rt_len > 0) is.read(&e.rel_type[0], rt_len); is.read(reinterpret_cast(&e.weight), 4); m.edges.push_back(std::move(e)); } // Phase 6: ttl + confidence (guarded — v5 files default to 0 / 1.0) int64_t ttl_val = 0; if (!is.read(reinterpret_cast(&ttl_val), 8)) return m; m.ttl = ttl_val; float conf_val = 1.0f; if (!is.read(reinterpret_cast(&conf_val), 4)) return m; m.confidence = conf_val; return m; } } // namespace feather