1// 2// model_package_info.mm 3// 4// Copyright © 2024 Apple Inc. All rights reserved. 5// 6// Please refer to the license found in the LICENSE file in the root directory of the source tree. 7 8#import "model_package_info.h" 9 10#import "ETCoreMLLogging.h" 11#import "objc_json_serde.h" 12#import "serde_json.h" 13 14namespace { 15struct ModelPackageInfoKeys { 16 struct Item { 17 constexpr static std::string_view kAuthorKey = "author"; 18 constexpr static std::string_view kDescriptionKey = "description"; 19 constexpr static std::string_view kNameKey = "name"; 20 constexpr static std::string_view kPathKey = "path"; 21 }; 22 23 constexpr static std::string_view kItemInfoEntriesKey = "itemInfoEntries"; 24 constexpr static std::string_view kRootModelIdentifierKey = "rootModelIdentifier"; 25}; 26} 27 28namespace executorchcoreml { 29namespace serde { 30namespace json { 31template <> 32struct Converter<ModelPackageInfo::Item> { 33 static void from_json(id json, ModelPackageInfo::Item& item) { 34 NSDictionary<NSString *, id> *json_dict = SAFE_CAST(json, NSDictionary); 35 if (!json_dict) { 36 return; 37 } 38 39 from_json_value(json_dict[to_string(ModelPackageInfoKeys::Item::kAuthorKey)], item.author); 40 from_json_value(json_dict[to_string(ModelPackageInfoKeys::Item::kDescriptionKey)], item.description); 41 from_json_value(json_dict[to_string(ModelPackageInfoKeys::Item::kNameKey)], item.name); 42 from_json_value(json_dict[to_string(ModelPackageInfoKeys::Item::kPathKey)], item.path); 43 } 44}; 45 46template <> 47struct Converter<ModelPackageInfo> { 48 static void from_json(id json, ModelPackageInfo& package_info) { 49 NSDictionary<NSString *, id> *json_dict = SAFE_CAST(json, NSDictionary); 50 if (!json_dict) { 51 return; 52 } 53 54 from_json_value(json_dict[to_string(ModelPackageInfoKeys::kRootModelIdentifierKey)], package_info.root_model_identifier); 55 from_json_value(json_dict[to_string(ModelPackageInfoKeys::kItemInfoEntriesKey)], package_info.items); 56 } 57}; 58} 59} 60} 61 62namespace executorchcoreml { 63std::optional<ModelPackageInfo> ModelPackageInfo::make(NSURL* model_package_url, 64 NSFileManager* fm, 65 NSError * __autoreleasing *error) noexcept { 66 NSURL *manifest_url = [model_package_url URLByAppendingPathComponent:@"manifest.json"].URLByStandardizingPath; 67 BOOL is_directory = NO; 68 if (![fm fileExistsAtPath:manifest_url.path isDirectory:&is_directory] || is_directory) { 69 ETCoreMLLogErrorAndSetNSError(error, 0, "%@ is broken, manifest doesn't exist.", model_package_url.lastPathComponent); 70 return std::nullopt; 71 } 72 73 NSData *data = [NSData dataWithContentsOfURL:manifest_url options:NSDataReadingMappedIfSafe error:error]; 74 if (!data) { 75 return std::nullopt; 76 } 77 78 id json_dictionary = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0 error:error]; 79 if (!json_dictionary) { 80 return std::nullopt; 81 } 82 83 ModelPackageInfo info; 84 serde::json::from_json_value(json_dictionary, info); 85 return info; 86} 87} 88